diff --git a/README.txt b/README.txt index 95b1fd8..12abb36 100644 --- a/README.txt +++ b/README.txt @@ -1,532 +1,540 @@ Name qhull, rbox 2012.1 2012/02/18 Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection Documentation: html/index.htm http://www.qhull.org/html Available from: [out-of-date] News and a paper: Version 1 (simplicial only): Purpose Qhull is a general dimension convex hull program that reads a set of points from stdin, and outputs the smallest convex set that contains the points to stdout. It also generates Delaunay triangulations, Voronoi diagrams, furthest-site Voronoi diagrams, and halfspace intersections about a point. Rbox is a useful tool in generating input for Qhull; it generates hypercubes, diamonds, cones, circles, simplices, spirals, lattices, and random points. Qhull produces graphical output for Geomview. This helps with understanding the output. Environment requirements Qhull and rbox should run on all 32-bit and 64-bit computers. Use an ANSI C or C++ compiler to compile the program. The software is self-contained. It comes with examples and test scripts. Qhull's C++ interface uses the STL. The C++ test program uses QTestLib from Nokia's Qt Framework. Qhull's C++ interface may change without notice. Eventually, it will move into the qhull shared library. Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt before using or distributing Qhull. To cite Qhull, please use Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull algorithm for convex hulls," ACM Trans. on Mathematical Software, 22(4):469-483, Dec 1996, http://www.qhull.org. To contribute to Qhull Qhull is on Gitorious (http://gitorious.org:qhull, git@gitorious.org:qhull/qhull.git) For internal documentation, see html/qh-code.htm To install Qhull Qhull is precompiled for Windows, otherwise it needs compilation. Besides makefiles for gcc, qhull includes CMakeLists.txt for CMake, vcproj/sln files for Microsoft Visual Studio, and .pro files for Qt Creator. It compiles with mingw. Install and build instructions follow. See the end of this document for a list of distributed files. ----------------- Installing Qhull on Windows 7 (32- or 64-bit), Windows XP, and Windows NT The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaUnay.exe, qhalf.exe, qvoronoi.exe, testqset.exe, user_eg*.exe, documentation files, and source files. To install Qhull: - Unzip the files into a directory. You may use WinZip32 - Click on QHULL-GO or open a command window into Qhull's bin directory. To uninstall Qhull - Delete the qhull directory To learn about Qhull: - Execute 'qconvex' for a synopsis and examples. - Execute 'rbox 10 | qconvex' to compute the convex hull of 10 random points. - Execute 'rbox 10 | qconvex i TO file' to write results to 'file'. - Browse the documentation: qhull\html\index.htm - If an error occurs, Windows sends the error to stdout instead of stderr. Use 'TO xxx' to send normal output to xxx and error output to stdout To improve the command window - Double-click the window bar to increase the size of the window - Right-click the window bar - Select Properties - Check QuickEdit Mode Select text with right-click or Enter Paste text with right-click - Change Font to Lucinda Console - Change Layout to Screen Buffer Height 999, Window Size Height 55 - Change Colors to Screen Background White, Screen Text Black - Click OK - Select 'Modify shortcut that started this window', then OK If you use qhull a lot, install MSYS (www.mingw.org), Road Bash (www.qhull.org/bash), or Cygwin (www.cygwin.com). ----------------- Installing Qhull on Unix with gcc To build Qhull, static libraries, shared library, and C++ interface - Extract Qhull from qhull...tgz or qhull...zip - make - export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH Or, to build Qhull and libqhullstatic.a - Extract Qhull from qhull...tgz or qhull...zip - cd src/libqhull - make The Makefiles may be edited for other compilers. If 'testqset' exits with an error, qhull is broken ----------------- Installing Qhull with CMake 2.6 or later To build Qhull, static libraries, shared library, and C++ interface - Extract Qhull from qhull...tgz or qhull...zip - cd build - cmake .. - make - make install On Windows, CMake installs to C:/Program Files/qhull See CMakeLists.txt for further build instructions ----------------- Installing Qhull with Qt To build Qhull, static libraries, shared library, C++ interface, and C++ test - Extract Qhull from qhull...tgz or qhull...zip - cd src - qmake - make ----------------- Installing Qhull with Autoconf [WARNING out-of-date] The tar.gz tarball contains documentation, source files, and a config directory [R. Laboissiere]. [Nov 2011] Qhull 2009.1.2 does not include the C++ interface To install Qhull - Extract the files - ./configure - make - make install ------------------- Working with Qhull's C++ interface Qhull's C++ interface is likely to change. Stay current with Gitorious. To clone Qhull's next branch from http://gitorious.org/qhull git init git clone git://gitorious.org/qhull/qhull.git cd qhull git checkout next ... git pull origin next + + Examples of using the C++ interface + user_eg3.cpp + qhulltest/*_test.cpp + Compile qhullcpp and libqhullr with the same compiler. These libraries use the + C routines setjmp() and longjmp() for error handling. They must be compiled with the + same compiler. + ------------------ Compiling Qhull with Microsoft Visual C++ 2005 or later To compile Qhull with Microsoft Visual C++ - Extract Qhull from Gitorious, qhull...tgz, or qhull...zip - Load solution build/qhull.sln - Build - Project qhulltest requires Qt for DevStudio (http://qt.nokia.com/downloads) Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/4.7.4) If incorrect, precompile will fail with 'Can not locate the file specified' ----------------- Compiling Qhull with Qt Creator Qt (http://qt.nokia.com) is a C++ framework for Windows, Linux, and Macintosh Qhull uses QTestLib to test qhull's C++ interface (qhulltest) To compile Qhull with Qt Creator - Extract Qhull from Gitorious, qhull...tgz, or qhull...zip - Download the Qt SDK from Nokia (http://qt.nokia.com/downloads) - Start Qt Creator - Load src/qhull-all.pro - Build ----------------- Compiling Qhull with mingw on Windows To compile Qhull with MINGW - Extract Qhull from Gitorious, qhull...tgz, or qhull...zip - Install Road Bash (http://www.qhull.org/bash) or install MSYS (http://www.mingw.org/wiki/msys) - Install MINGW (http://www.mingw.org/). Mingw is included with Qt SDK. - make ----------------- Compiling Qhull with cygwin on Windows To compile Qhull with cygwin - Extract Qhull from Gitorious, qhull...tgz, or qhull...zip - Install cygwin (http://www.cygwin.com) - Include packages for gcc, make, ar, and ln - make ----------------- Compiling from Makfile without gcc The file, qhull-src.tgz, contains documentation and source files for qhull and rbox. To unpack the gzip file - tar zxf qhull-src.tgz - cd qhull Compiling qhull and rbox with Makefile - in Makefile, check the CC, CCOPTS1, PRINTMAN, and PRINTC defines - the defaults are gcc and enscript - CCOPTS1 should include the ANSI flag. It defines __STDC__ - in user.h, check the definitions of qh_SECticks and qh_CPUclock. - use '#define qh_CLOCKtype 2' for timing runs longer than 1 hour - type: make - this builds: qhull qconvex qdelaunay qhalf qvoronoi rbox libqhull.a - type: make doc - this prints the man page - See also qhull/html/index.htm - if your compiler reports many errors, it is probably not a ANSI C compiler - you will need to set the -ansi switch or find another compiler - if your compiler warns about missing prototypes for fprintf() etc. - this is ok, your compiler should have these in stdio.h - if your compiler warns about missing prototypes for memset() etc. - include memory.h in qhull_a.h - if your compiler reports "global.c: storage size of 'qh_qh' isn't known" - delete the initializer "={0}" in global.c, stat.c and mem.c - if your compiler warns about "stat.c: improper initializer" - this is ok, the initializer is not used - if you have trouble building libqhull.a with 'ar' - try 'make -f Makefile.txt qhullx' - if the code compiles, the qhull test case will automatically execute - if an error occurs, there's an incompatibility between machines - If you can, try a different compiler - You can turn off the Qhull memory manager with qh_NOmem in mem.h - You can turn off compiler optimization (-O2 in Makefile) - If you find the source of the problem, please let us know - to install the programs and their man pages: - define MANDIR and BINDIR - type 'make install' - if you have Geomview (www.geomview.org) - try 'rbox 100 | qconvex G >a' and load 'a' into Geomview - run 'q_eg' for Geomview examples of Qhull output (see qh-eg.htm) ------------------ Compiling on other machines and compilers Qhull compiles with Borland C++ 5.0 bcc32. A Makefile is included. Execute 'make -f Mborland'. If you use the Borland IDE, set the ANSI option in Options:Project:Compiler:Source:Language-compliance. Qhull compiles with Borland C++ 4.02 for Win32 and DOS Power Pack. Use 'make -f Mborland -D_DPMI'. Qhull 1.0 compiles with Borland C++ 4.02. For rbox 1.0, use "bcc32 -WX -w- -O2-e -erbox -lc rbox.c". Use the same options for Qhull 1.0. [D. Zwick] Qhull compiles with Metrowerks C++ 1.7 with the ANSI option. If you turn on full warnings, the compiler will report a number of unused variables, variables set but not used, and dead code. These are intentional. For example, variables may be initialized (unnecessarily) to prevent warnings about possible use of uninitialized variables. Qhull compiles on the Power Macintosh with Metrowerk's C compiler. It uses the SIOUX interface to read point coordinates and return output. There is no graphical output. For project files, see 'Compiling a custom build'. Instead of using SIOUX, Qhull may be embedded within an application. Some users have reported problems with compiling Qhull under Irix 5.1. It compiles under other versions of Irix. If you have troubles with the memory manager, you can turn it off by defining qh_NOmem in mem.h. ----------------- Distributed files README.txt // Instructions for installing Qhull REGISTER.txt // Qhull registration COPYING.txt // Copyright notice QHULL-GO.lnk // Windows icon for eg/qhull-go.bat Announce.txt // Announcement CMakeLists.txt // CMake build file (2.6 or later) File_id.diz // Package descriptor index.htm // Home page Makefile // Makefile for gcc and other compilers qhull*.md5sum // md5sum for all files bin/* // Qhull executables and dll (.zip only) build/qhull.sln // DevStudio solution and project files (2005 or later) build/*.vcproj config/* // Autoconf files for creating configure (Unix only) eg/* // Test scripts and geomview files from q_eg html/index.htm // Manual html/qh-faq.htm // Frequently asked questions html/qh-get.htm // Download page html/qhull-cpp.xml // C++ style notes as a Road FAQ (www.qhull.org/road) src/Changes.txt // Change history for Qhull and rbox src/qhull-all.pro // Qt project eg/ q_eg // shell script for Geomview examples (eg.01.cube) q_egtest // shell script for Geomview test examples q_test // shell script to test qhull q_test-ok.txt // output from q_test qhulltest-ok.txt // output from qhulltest (Qt only) rbox consists of (bin, html): rbox.exe // Win32 executable (.zip only) rbox.htm // html manual rbox.man // Unix man page rbox.txt qhull consists of (bin, html): qhull.exe // Win32 executables and dlls (.zip only) qconvex.exe qdelaunay.exe qhalf.exe qvoronoi.exe qhull.dll qhull_p.dll qhull-go.bat // command window qconvex.htm // html manual qdelaun.htm qdelau_f.htm qhalf.htm qvoronoi.htm qvoron_f.htm qh-eg.htm qh-code.htm qh-impre.htm index.htm qh-opt*.htm qh-quick.htm qh--*.gif // images for manual normal_voronoi_knauss_oesterle.jpg qhull.man // Unix man page qhull.txt bin/ msvcr80.dll // Visual C++ redistributable file (.zip only) src/ qhullr/unix_r.c // Qhull and rbox applications using libqhullstatic_r.a rboxr/rbox_r.c qhull/unix.c // Qhull and rbox applications qconvex/qconvex.c qhalf/qhalf.c qdelaunay/qdelaunay.c qvoronoi/qvoronoi.c rbox/rbox.c user_eg/user_eg.c // example of using qhull_r.dll user_eg2/user_eg2.c // example of using qhull.dll from a user program user_eg3/user_eg3.cpp // example of Qhull's C++ interface with libqhullstatic_r.a qhulltest/qhulltest.cpp // Test of Qhull's C++ interface using Qt's QTestLib qhull-*.pri // Include files for Qt projects testqset/testqset.c // Test of qset_r.c and mem_r.c user_eg7/user_eg7.c // example of using deprecated qhull_p.dll (requires -Dqh_QHpointer) user_eg8/user_eg8.c // example of using deprecated qhull.dll from a user program user_eg9/user_eg9.cpp // example of Qhull's deprecated C++ interface with libqhullstatic_p.a qhullptest/qhullptest.cpp // Test of Qhull's deprecated C++ interface with libqhullstatic_p.a testqsetp/testqsetp.c // Test of deprecated qset.c and mem.c src/libqhull libqhull.pro // Qt project for shared library (qhull.dll) index.htm // design documentation for libqhull qh-*.htm qhull-exports.def // Export Definition file for Visual C++ Makefile // Simple gcc Makefile for qhull and libqhullstatic.a Mborland // Makefile for Borland C++ 5.0 libqhull.h // header file for qhull user.h // header file of user definable constants libqhull.c // Quickhull algorithm with partitioning user.c // user re-definable functions usermem.c userprintf.c userprintf_rbox.c qhull_a.h // include files for libqhull/*.c geom.c // geometric routines geom2.c geom.h global.c // global variables io.c // input-output routines io.h mem.c // memory routines, this is stand-alone code mem.h merge.c // merging of non-convex facets merge.h poly.c // polyhedron routines poly2.c poly.h qset.c // set routines, this only depends on mem.c qset.h random.c // utilities w/ Park & Miller's random number generator random.h rboxlib.c // point set generator for rbox stat.c // statistics stat.h src/libqhullp libqhullp.pro // Qt project for shared library (qhull_p.dll) qhull_p-exports.def // Export Definition file for Visual C++ src/libqhullstatic/ libqhullstatic.pro // Qt project for static library src/libqhullstaticp/ libqhullstaticp.pro // Qt project for static library with qh_QHpointer src/libqhullcpp/ libqhullcpp.pro // Qt project for static C++ library Qhull.cpp // Call libqhull.c from C++ Qhull.h qt-qhull.cpp // Supporting methods for Qt qhull_interface.cpp // Another approach to C++ Coordinates.cpp // input classes Coordinates.h PointCoordinates.cpp PointCoordinates.h RboxPoints.cpp // call rboxlib.c from C++ RboxPoints.h QhullFacet.cpp // data structure classes QhullFacet.h QhullHyperplane.cpp QhullHyperplane.h QhullPoint.cpp QhullPoint.h QhullQh.cpp QhullStat.cpp QhullStat.h QhullVertex.cpp QhullVertex.h QhullFacetList.cpp // collection classes QhullFacetList.h QhullFacetSet.cpp QhullFacetSet.h QhullIterator.h QhullLinkedList.h QhullPoints.cpp QhullPoints.h QhullPointSet.cpp QhullPointSet.h QhullRidge.cpp QhullRidge.h QhullSet.cpp QhullSet.h QhullSets.h QhullVertexSet.cpp QhullVertexSet.h functionObjects.h // supporting classes QhullError.cpp QhullError.h QhullQh.cpp QhullQh.h UsingLibQhull.cpp UsingLibQhull.h src/qhulltest/ qhulltest.pro // Qt project for test of C++ interface Coordinates_test.cpp // Test of each class PointCoordinates_test.cpp Point_test.cpp QhullFacetList_test.cpp QhullFacetSet_test.cpp QhullFacet_test.cpp QhullHyperplane_test.cpp QhullLinkedList_test.cpp QhullPointSet_test.cpp QhullPoints_test.cpp QhullPoint_test.cpp QhullRidge_test.cpp QhullSet_test.cpp QhullVertexSet_test.cpp QhullVertex_test.cpp Qhull_test.cpp RboxPoints_test.cpp UsingLibQhull_test.cpp src/road/ RoadError.cpp // Supporting base classes RoadError.h RoadLogEvent.cpp RoadLogEvent.h RoadTest.cpp // Run multiple test files with QTestLib RoadTest.h src/testqset/ testqset.pro // Qt project for test qset.c with mem.c testqset.c ----------------- Authors: C. Bradford Barber Hannu Huhdanpaa (Version 1.0) bradb@shore.net hannu@qhull.org Qhull 1.0 and 2.0 were developed under NSF grants NSF/DMS-8920161 and NSF-CCR-91-15793 750-7504 at the Geometry Center and Harvard University. If you find Qhull useful, please let us know. diff --git a/html/index.htm b/html/index.htm index a87b0c6..f4e1a46 100644 --- a/html/index.htm +++ b/html/index.htm @@ -1,772 +1,772 @@ Qhull manual

Up: Home page for Qhull
Up:News about Qhull
Up: FAQ about Qhull
To: Qhull manual: Table of Contents (please wait while loading)
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[random-fixed] Qhull manual

Qhull is a general dimension code for computing convex hulls, Delaunay triangulations, halfspace intersections about a point, Voronoi diagrams, furthest-site Delaunay triangulations, and furthest-site Voronoi diagrams. These structures have applications in science, engineering, statistics, and mathematics. See Fukuda's introduction to convex hulls, Delaunay triangulations, Voronoi diagrams, and linear programming. For a detailed introduction, see O'Rourke ['94], Computational Geometry in C.

There are six programs. Except for rbox, they use the same code.

  • qconvex -- convex hulls
  • qdelaunay -- Delaunay triangulations and furthest-site Delaunay triangulations
  • qhalf -- halfspace intersections about a point
  • qhull -- all structures with additional options
  • qvoronoi -- Voronoi diagrams and furthest-site Voronoi diagrams
  • rbox -- generate point distributions for qhull

Qhull implements the Quickhull algorithm for computing the convex hull. Qhull includes options for hull volume, facet area, multiple output formats, and graphical output. It can approximate a convex hull.

Qhull handles roundoff errors from floating point arithmetic. It generates a convex hull with "thick" facets. A facet's outer plane is clearly above all of the points; its inner plane is clearly below the facet's vertices. Any exact convex hull must lie between the inner and outer plane.

Qhull uses merged facets, triangulated output, or joggled input. Triangulated output triangulates non-simplicial, merged facets. Joggled input also guarantees simplicial output, but it is less accurate than merged facets. For merged facets, Qhull reports the maximum outer and inner plane.

Brad Barber, Arlington, MA

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»Qhull manual: Table of Contents

»When to use Qhull

Qhull constructs convex hulls, Delaunay triangulations, halfspace intersections about a point, Voronoi diagrams, furthest-site Delaunay triangulations, and furthest-site Voronoi diagrams.

For convex hulls and halfspace intersections, Qhull may be used for 2-d upto 8-d. For Voronoi diagrams and Delaunay triangulations, Qhull may be used for 2-d upto 7-d. In higher dimensions, the size of the output grows rapidly and Qhull does not work well with virtual memory. If n is the size of the input and d is the dimension (d>=3), the size of the output and execution time grows by n^(floor(d/2) [see Performance]. For example, do not try to build a 16-d convex hull of 1000 points. It will have on the order of 1,000,000,000,000,000,000,000,000 facets.

On a 600 MHz Pentium 3, Qhull computes the 2-d convex hull of 300,000 cocircular points in 11 seconds. It computes the 2-d Delaunay triangulation and 3-d convex hull of 120,000 points in 12 seconds. It computes the 3-d Delaunay triangulation and 4-d convex hull of 40,000 points in 18 seconds. It computes the 4-d Delaunay triangulation and 5-d convex hull of 6,000 points in 12 seconds. It computes the 5-d Delaunay triangulation and 6-d convex hull of 1,000 points in 12 seconds. It computes the 6-d Delaunay triangulation and 7-d convex hull of 300 points in 15 seconds. It computes the 7-d Delaunay triangulation and 8-d convex hull of 120 points in 15 seconds. It computes the 8-d Delaunay triangulation and 9-d convex hull of 70 points in 15 seconds. It computes the 9-d Delaunay triangulation and 10-d convex hull of 50 points in 17 seconds. The 10-d convex hull of 50 points has about 90,000 facets.

Qhull does not support constrained Delaunay triangulations, triangulation of non-convex surfaces, mesh generation of non-convex objects, or medium-sized inputs in 9-D and higher.

This is a big package with many options. It is one of the fastest available. It is the only 3-d code that handles precision problems due to floating point arithmetic. For example, it implements the identity function for extreme points (see Imprecision in Qhull).

If you need a short code for convex hull, Delaunay triangulation, or Voronoi volumes consider Clarkson's hull program. If you need 2-d Delaunay triangulations consider Shewchuk's triangle program. It is much faster than Qhull and it allows constraints. Both programs use exact arithmetic. They are in http://www.netlib.org/voronoi/. Qhull version 1.0 may also meet your needs. It detects precision problems, but does not handle them.

Leda is a library for writing computational geometry programs and other combinatorial algorithms. It includes routines for computing 3-d convex hulls, 2-d Delaunay triangulations, and 3-d Delaunay triangulations. It provides rational arithmetic and graphical output. It runs on most platforms.

If your problem is in high dimensions with a few, non-simplicial facets, try Fukuda's cdd. It is much faster than Qhull for these distributions.

Custom software for 2-d and 3-d convex hulls may be faster than Qhull. Custom software should use less memory. Qhull uses general-dimension data structures and code. The data structures support non-simplicial facets.

Qhull is not suitable for mesh generation or triangulation of arbitrary surfaces. You may use Qhull if the surface is convex or completely visible from an interior point (e.g., a star-shaped polyhedron). First, project each site to a sphere that is centered at the interior point. Then, compute the convex hull of the projected sites. The facets of the convex hull correspond to a triangulation of the surface. For mesh generation of arbitrary surfaces, see Schneiders' Finite Element Mesh Generation.

Qhull is not suitable for constrained Delaunay triangulations. With a lot of work, you can write a program that uses Qhull to add constraints by adding additional points to the triangulation.

Qhull is not suitable for the subdivision of arbitrary objects. Use qdelaunay to subdivide a convex object.

»Description of Qhull

»definition

The convex hull of a point set P is the smallest convex set that contains P. If P is finite, the convex hull defines a matrix A and a vector b such that for all x in P, Ax+b <= [0,...].

Qhull computes the convex hull in 2-d, 3-d, 4-d, and higher dimensions. Qhull represents a convex hull as a list of facets. Each facet has a set of vertices, a set of neighboring facets, and a halfspace. A halfspace is defined by a unit normal and an offset (i.e., a row of A and an element of b).

Qhull accounts for round-off error. It returns "thick" facets defined by two parallel hyperplanes. The outer planes contain all input points. The inner planes exclude all output vertices. See Imprecise convex hulls.

Qhull may be used for the Delaunay triangulation or the Voronoi diagram of a set of points. It may be used for the intersection of halfspaces.

»input format

The input data on stdin consists of:

  • first line contains the dimension
  • second line contains the number of input points
  • remaining lines contain point coordinates

For example:

     3  #sample 3-d input
     5
     0.4 -0.5 1.0
     1000 -1e-5 -100
     0.3 0.2 0.1
     1.0 1.0 1.0
     0 0 0
 

Input may be entered by hand. End the input with a control-D (^D) character.

To input data from a file, use I/O redirection or 'TI file'. The filename may not include spaces or quotes.

A comment starts with a non-numeric character and continues to the end of line. The first comment is reported in summaries and statistics. With multiple qhull commands, use option 'FQ' to place a comment in the output.

The dimension and number of points can be reversed. Comments and line breaks are ignored. Error reporting is better if there is one point per line.

»option format

Use options to specify the output formats and control Qhull. The qhull program takes all options. The other programs use a subset of the options. They disallow experimental and inappropriate options.

  • qconvex == qhull
  • qdelaunay == qhull d Qbb
  • qhalf == qhull H
  • qvoronoi == qhull v Qbb

Single letters are used for output formats and precision constants. The other options are grouped into menus for formats ('F'), Geomview ('G '), printing ('P'), Qhull control ('Q '), and tracing ('T'). The menu options may be listed together (e.g., 'GrD3' for 'Gr' and 'GD3'). Options may be in any order. Capitalized options take a numeric argument (except for 'PG' and 'F' options). Use option 'FO' to print the selected options.

Qhull uses zero-relative indexing. If there are n points, the index of the first point is 0 and the index of the last point is n-1.

The default options are:

  • summary output ('s')
  • merged facets ('C-0' in 2-d, 3-d, 4-d; 'Qx' in 5-d and up)

Except for bounding box ('Qbk:n', etc.), drop facets ('Pdk:n', etc.), and Qhull command ('FQ'), only the last occurence of an option counts. Bounding box and drop facets may be repeated for each dimension. Option 'FQ' may be repeated any number of times.

The Unix tcsh and ksh shells make it easy to try out different options. In Windows 95, use a command window with doskey and a window scroller (e.g., peruse).

»output format

To write the results to a file, use I/O redirection or 'TO file'. Windows 95 users should use 'TO file' or the console. If a filename is surrounded by single quotes, it may include spaces.

The default output option is a short summary ('s') to stdout. There are many others (see output and formats). You can list vertex incidences, vertices and facets, vertex coordinates, or facet normals. You can view Qhull objects with Geomview, Mathematica, or Maple. You can print the internal data structures. You can call Qhull from your application (see Qhull library).

For example, 'qhull o' lists the vertices and facets of the convex hull.

Error messages and additional summaries ('s') go to stderr. Unless redirected, stderr is the console.

»algorithm

Qhull implements the Quickhull algorithm for convex hull [Barber et al. '96]. This algorithm combines the 2-d Quickhull algorithm with the n-d beneath-beyond algorithm [c.f., Preparata & Shamos '85]. It is similar to the randomized algorithms of Clarkson and others [Clarkson & Shor '89; Clarkson et al. '93; Mulmuley '94]. For a demonstration, see How Qhull adds a point. The main advantages of Quickhull are output sensitive performance (in terms of the number of extreme points), reduced space requirements, and floating-point error handling.

»data structures

Qhull produces the following data structures for dimension d:

  • A coordinate is a real number in floating point format.
  • A point is an array of d coordinates. With option 'QJ', the coordinates are joggled by a small amount.
  • A vertex is an input point.
  • A hyperplane is d normal coefficients and an offset. The length of the normal is one. The hyperplane defines a halfspace. If V is a normal, b is an offset, and x is a point inside the convex hull, then Vx+b <0.
  • An outer plane is a positive offset from a hyperplane. When Qhull is done, all points will be below all outer planes.
  • An inner plane is a negative offset from a hyperplane. When Qhull is done, all vertices will be above the corresponding inner planes.
  • An orientation is either 'top' or 'bottom'. It is the topological equivalent of a hyperplane's geometric orientation.
  • A simplicial facet is a set of d neighboring facets, a set of d vertices, a hyperplane equation, an inner plane, an outer plane, and an orientation. For example in 3-d, a simplicial facet is a triangle.
  • A centrum is a point on a facet's hyperplane. A centrum is the average of a facet's vertices. Neighboring facets are convex if each centrum is below the neighbor facet's hyperplane.
  • A ridge is a set of d-1 vertices, two neighboring facets, and an orientation. For example in 3-d, a ridge is a line segment.
  • A non-simplicial facet is a set of ridges, a hyperplane equation, a centrum, an outer plane, and an inner plane. The ridges determine a set of neighboring facets, a set of vertices, and an orientation. Qhull produces a non-simplicial facet when it merges two facets together. For example, a cube has six non-simplicial facets.

For examples, use option 'f'. See polyhedron operations for further design documentation.

»Imprecision in Qhull

See Imprecision in Qhull.

»Geomview, Qhull's graphical viewer

Geomview is an interactive geometry viewing program for Linux, SGI workstations, Sun workstations, AIX workstations, NeXT workstations, and X-windows. It is an open source project under SourceForge. Besides a 3-d viewer, it includes a 4-d viewer, an n-d viewer and many features for viewing mathematical objects. You may need to ftp ndview from the newpieces directory.

»Description of Qhull examples

See Examples. Some of the examples have pictures .

»Options for using Qhull

See Options.

»Qhull internals

See Internals.

»What to do if something goes wrong

Please report bugs to qhull_bug@qhull.org . Please report if Qhull crashes. Please report if Qhull generates an "internal error". Please report if Qhull produces a poor approximate hull in 2-d, 3-d or 4-d. Please report documentation errors. Please report missing or incorrect links.

If you do not understand something, try a small example. The rbox program is an easy way to generate test cases. The Geomview program helps to visualize the output from Qhull.

If Qhull does not compile, it is due to an incompatibility between your system and ours. The first thing to check is that your compiler is ANSI standard. Qhull produces a compiler error if __STDC__ is not defined. You may need to set a flag (e.g., '-A' or '-ansi').

If Qhull compiles but crashes on the test case (rbox D4), there's still incompatibility between your system and ours. Sometimes it is due to memory management. This can be turned off with qh_NOmem in mem.h. Please let us know if you figure out how to fix these problems.

If you doubt the output from Qhull, add option 'Tv'. It checks that every point is inside the outer planes of the convex hull. It checks that every facet is convex with its neighbors. It checks the topology of the convex hull.

Qhull should work on all inputs. It may report precision errors if you turn off merged facets with option 'Q0'. This can get as bad as facets with flipped orientation or two facets with the same vertices. You'll get a long help message if you run into such a case. They are easy to generate with rbox.

If you do find a problem, try to simplify it before reporting the error. Try different size inputs to locate the smallest one that causes an error. You're welcome to hunt through the code using the execution trace ('T4') as a guide. This is especially true if you're incorporating Qhull into your own program.

When you report an error, please attach a data set to the end of your message. Include the options that you used with Qhull, the results of option 'FO', and any messages generated by Qhull. This allows me to see the error for myself. Qhull is maintained part-time.

»Email

Please send correspondence to Brad Barber at qhull@qhull.org and report bugs to qhull_bug@qhull.org . Let me know how you use Qhull. If you mention it in a paper, please send a reference and abstract.

If you would like to get Qhull announcements (e.g., a new version) and news (any bugs that get fixed, etc.), let us know and we will add you to our mailing list. If you would like to communicate with other Qhull users, I will add you to the qhull_users alias. For Internet news about geometric algorithms and convex hulls, look at comp.graphics.algorithms and sci.math.num-analysis. For Qhull news look at qhull-news.html.

»Authors

    C. Bradford Barber                    Hannu Huhdanpaa
    bradb@shore.net                       hannu@qhull.org
 

»Acknowledgments

A special thanks to David Dobkin for his guidance. A special thanks to Albert Marden, Victor Milenkovic, the Geometry Center, and Harvard University for supporting this work.

A special thanks to Mark Phillips, Robert Miner, and Stuart Levy for running the Geometry Center web site long after the Geometry Center closed. Stuart moved the web site to the University of Illinois at Champaign-Urbana. Mark and Robert are founders of Geometry Technologies. Mark, Stuart, and Tamara Munzner are the original authors of Geomview.

A special thanks to Endocardial Solutions, Inc. of St. Paul, Minnesota for their support of the internal documentation (src/libqhull/index.htm). They use Qhull to build 3-d models of heart chambers.

Qhull 1.0 and 2.0 were developed under National Science Foundation grants NSF/DMS-8920161 and NSF-CCR-91-15793 750-7504. If you find it useful, please let us know.

The Geometry Center was supported by grant DMS-8920161 from the National Science Foundation, by grant DOE/DE-FG02-92ER25137 from the Department of Energy, by the University of Minnesota, and by Minnesota Technology, Inc.

»References

Aurenhammer, F., "Voronoi diagrams -- A survey of a fundamental geometric data structure," ACM Computing Surveys, 1991, 23:345-405.

Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The Quickhull Algorithm for Convex Hulls," ACM Transactions on Mathematical Software, 22(4):469-483, Dec 1996, www.qhull.org [http://portal.acm.org; http://citeseerx.ist.psu.edu].

Clarkson, K.L. and P.W. Shor, "Applications of random sampling in computational geometry, II", Discrete Computational Geometry, 4:387-421, 1989

Clarkson, K.L., K. Mehlhorn, and R. Seidel, "Four results on randomized incremental construction," Computational Geometry: Theory and Applications, vol. 3, p. 185-211, 1993.

Devillers, et. al., "Walking in a triangulation," ACM Symposium on Computational Geometry, June 3-5,2001, Medford MA.

Dobkin, D.P. and D.G. Kirkpatrick, "Determining the separation of preprocessed polyhedra--a unified approach," in Proc. 17th Inter. Colloq. Automata Lang. Program., in Lecture Notes in Computer Science, Springer-Verlag, 443:400-413, 1990.

Edelsbrunner, H, Geometry and Topology for Mesh Generation, Cambridge University Press, 2001.

Gartner, B., "Fast and robust smallest enclosing balls", Algorithms - ESA '99, LNCS 1643.

Fortune, S., "Computational geometry," in R. Martin, editor, Directions in Geometric Computation, Information Geometers, 47 Stockers Avenue, Winchester, SO22 5LB, UK, ISBN 1-874728-02-X, 1993.

Milenkovic, V., "Robust polygon modeling," Computer-Aided Design, vol. 25, p. 546-566, September 1993.

Mucke, E.P., I. Saias, B. Zhu, Fast randomized point location without preprocessing in Two- and Three-dimensional Delaunay Triangulations, ACM Symposium on Computational Geometry, p. 274-283, 1996 [GeomDir].

Mulmuley, K., Computational Geometry, An Introduction Through Randomized Algorithms, Prentice-Hall, NJ, 1994.

O'Rourke, J., Computational Geometry in C, Cambridge University Press, 1994.

Preparata, F. and M. Shamos, Computational Geometry, Springer-Verlag, New York, 1985.


Up: Home page for Qhull
Up:News about Qhull
Up: FAQ about Qhull
To: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Dn: Imprecision in Qhull
Dn: Description of Qhull examples
Dn: Qhull internals
Dn: Qhull functions, macros, and data structures


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qconvex.htm b/html/qconvex.htm index 460e52a..a9cd08c 100644 --- a/html/qconvex.htm +++ b/html/qconvex.htm @@ -1,628 +1,628 @@ qconvex -- convex hull Up: Home page for Qhull
Up: Qhull manual -- Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[cone]qconvex -- convex hull

The convex hull of a set of points is the smallest convex set containing the points. See the detailed introduction by O'Rourke ['94]. See Description of Qhull and How Qhull adds a point.

Example: rbox 10 D3 | qconvex s o TO result
Compute the 3-d convex hull of 10 random points. Write a summary to the console and the points and facets to 'result'.
 
Example: rbox c | qconvex n
Print the normals for each facet of a cube.
 
Example: rbox c | qconvex i Qt
Print the triangulated facets of a cube.
 
Example: rbox y 500 W0 | qconvex
Compute the convex hull of a simplex with 500 points on its surface.
 
Example: rbox x W1e-12 1000 | qconvex QR0
Compute the convex hull of 1000 points near the surface of a randomly rotated simplex. Report the maximum thickness of a facet.
 
Example: rbox 1000 s | qconvex s FA
Compute the convex hull of 1000 cospherical points. Verify the results and print a summary with the total area and volume.
 
Example: rbox d D12 | qconvex QR0 FA
Compute the convex hull of a 12-d diamond. Randomly rotate the input. Note the large number of facets and the small volume.
 
Example: rbox c D7 | qconvex FA TF1000
Compute the convex hull of the 7-d hypercube. Report on progress every 1000 facets. Computing the convex hull of the 9-d hypercube takes too much time and space.
 
Example: rbox c d D2 | qconvex Qc s f Fx | more
Dump all fields of all facets for a square and a diamond. Also print a summary and a list of vertices. Note the coplanar points.
 

Except for rbox, all of the qhull programs compute a convex hull.

By default, Qhull merges coplanar facets. For example, the convex hull of a cube's vertices has six facets.

If you use 'Qt' (triangulated output), all facets will be simplicial (e.g., triangles in 2-d). For the cube example, it will have 12 facets. Some facets may be degenerate and have zero area.

If you use 'QJ' (joggled input), all facets will be simplicial. The corresponding vertices will be slightly perturbed and identical points will be joggled apart. Joggled input is less accurate that triangulated output.See Merged facets or joggled input.

The output for 4-d convex hulls may be confusing if the convex hull contains non-simplicial facets (e.g., a hypercube). See Why are there extra points in a 4-d or higher convex hull?

The 'qconvex' program is equivalent to 'qhull' in 2-d to 4-d, and 'qhull Qx' in 5-d and higher. It disables the following Qhull options: d v H Qbb Qf Qg Qm Qr Qu Qv Qx Qz TR E V Fp Gt Q0,etc. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»qconvex synopsis

 qconvex- compute the convex hull.
     input (stdin): dimension, number of points, point coordinates
     comments start with a non-numeric character
 
 options (qconvex.htm):
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Tv   - verify result: structure, convexity, and point inclusion
     .    - concise list of all options
     -    - one-line description of all options
 
 output options (subset):
     s    - summary of results (default)
     i    - vertices incident to each facet
     n    - normals with offsets
     p    - vertex coordinates (includes coplanar points if 'Qc')
     Fx   - extreme points (convex hull vertices)
     FA   - compute total area and volume
     o    - OFF format (dim, n, points, facets)
     G    - Geomview output (2-d, 3-d, and 4-d)
     m    - Mathematica output (2-d and 3-d)
     QVn  - print facets that include point n, -n if not
     TO file- output results to file, may be enclosed in single quotes
 
 examples:
     rbox c D2 | qconvex s n                    rbox c D2 | qconvex i
     rbox c D2 | qconvex o                      rbox 1000 s | qconvex s Tv FA
     rbox c d D2 | qconvex s Qc Fx              rbox y 1000 W0 | qconvex s n
     rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp
     rbox c D7 | qconvex FA TF1000
 

»qconvex input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

Use I/O redirection (e.g., qconvex < data.txt), a pipe (e.g., rbox 10 | qconvex), or the 'TI' option (e.g., qconvex TI data.txt).

Comments start with a non-numeric character. Error reporting is simpler if there is one point per line. Dimension and number of points may be reversed.

Here is the input for computing the convex hull of the unit cube. The output is the normals, one per facet.

rbox c > data

 3 RBOX c
 8
   -0.5   -0.5   -0.5
   -0.5   -0.5    0.5
   -0.5    0.5   -0.5
   -0.5    0.5    0.5
    0.5   -0.5   -0.5
    0.5   -0.5    0.5
    0.5    0.5   -0.5
    0.5    0.5    0.5
 

qconvex s n < data

 
 Convex hull of 8 points in 3-d:
 
   Number of vertices: 8
   Number of facets: 6
   Number of non-simplicial facets: 6
 
 Statistics for: RBOX c | QCONVEX s n
 
   Number of points processed: 8
   Number of hyperplanes created: 11
   Number of distance tests for qhull: 35
   Number of merged facets: 6
   Number of distance tests for merging: 84
   CPU seconds to compute hull (after input): 0.081
 
 4
 6
      0      0     -1   -0.5
      0     -1      0   -0.5
      1      0      0   -0.5
     -1      0      0   -0.5
      0      1      0   -0.5
      0      0      1   -0.5
 

»qconvex outputs

These options control the output of qconvex. They may be used individually or together.

 
Vertices
Fx
list extreme points (i.e., vertices). The first line is the number of extreme points. Each point is listed, one per line. The cube example has eight vertices.
Fv
list vertices for each facet. The first line is the number of facets. Each remaining line starts with the number of vertices. For the cube example, each facet has four vertices.
i
list vertices for each facet. The first line is the number of facets. The - remaining lines list the vertices for each facet. In 3-d and - higher, report cospherical sites by adding extra points.
+ remaining lines list the vertices for each facet. In 4-d and + higher, triangulate non-simplicial facets by adding an extra point.
 
 
Coordinates
o
print vertices and facets of the convex hull in OFF format. The first line is the dimension. The second line is the number of vertices, facets, and ridges. The vertex coordinates are next, followed by the facets. Each facet starts with the number of vertices. The cube example has four vertices per facet.
Ft
print a triangulation of the convex hull in OFF format. The first line is the dimension. The second line is the number of vertices and added points, followed by the number of facets and the number of ridges. The vertex coordinates are next, followed by the centrum coordinates. There is one centrum for each non-simplicial facet. The cube example has six centrums, one per square. Each facet starts with the number of vertices or centrums. In the cube example, each facet uses two vertices and one centrum.
p
print vertex coordinates. The first line is the dimension and the second line is the number of vertices. The following lines are the coordinates of each vertex. The cube example has eight vertices.
Qc p
print coordinates of vertices and coplanar points. The first line is the dimension. The second line is the number of vertices and coplanar points. The coordinates are next, one line per point. Use 'Qc Qi p' to print the coordinates of all points.
 
 
Facets
Fn
list neighboring facets for each facet. The first line is the number of facets. Each remaining line starts with the number of neighboring facets. The cube example has four neighbors per facet.
FN
list neighboring facets for each point. The first line is the total number of points. Each remaining line starts with the number of neighboring facets. Each vertex of the cube example has three neighboring facets. Use 'Qc Qi FN' to include coplanar and interior points.
Fa
print area for each facet. The first line is the number of facets. Facet area follows, one line per facet. For the cube example, each facet has area one.
FI
list facet IDs. The first line is the number of facets. The IDs follow, one per line.
 
 
Coplanar and interior points
Fc
list coplanar points for each facet. The first line is the number of facets. The remaining lines start with the number of coplanar points. A coplanar point is assigned to one facet.
Qi Fc
list interior points for each facet. The first line is the number of facets. The remaining lines start with the number of interior points. A coplanar point is assigned to one facet.
FP
print distance to nearest vertex for coplanar points. The first line is the number of coplanar points. Each remaining line starts with the point ID of a vertex, followed by the point ID of a coplanar point, its facet, and distance. Use 'Qc Qi FP' for coplanar and interior points.
 
 
Hyperplanes
n
print hyperplane for each facet. The first line is the dimension. The second line is the number of facets. Each remaining line is the hyperplane's coefficients followed by its offset.
Fo
print outer plane for each facet. The output plane is above all points. The first line is the dimension. The second line is the number of facets. Each remaining line is the outer plane's coefficients followed by its offset.
Fi
print inner plane for each facet. The inner plane of a facet is below its vertices. The first line is the dimension. The second line is the number of facets. Each remaining line is the inner plane's coefficients followed by its offset.
 
 
General
s
print summary for the convex hull. Use 'Fs' and 'FS' if you need numeric data.
FA
compute total area and volume for 's' and 'FS'
m
Mathematica output for the convex hull in 2-d or 3-d.
FM
Maple output for the convex hull in 2-d or 3-d.
G
Geomview output for the convex hull in 2-d, 3-d, or 4-d.
 
 
Scaling and rotation
Qbk:n
scale k'th coordinate to lower bound.
QBk:n
scale k'th coordinate to upper bound.
QbB
scale input to unit cube centered at the origin.
QRn
randomly rotate the input with a random seed of n. If n=0, the seed is the time. If n=-1, use time for the random seed, but do not rotate the input.
Qbk:0Bk:0
remove k'th coordinate from input. This computes the convex hull in one lower dimension.

»qconvex controls

These options provide additional control:

Qt
triangulated output. Qhull triangulates non-simplicial facets. It may produce degenerate facets of zero area.
QJ
joggle the input instead of merging facets. This guarantees simplicial facets (e.g., triangles in 3-d). It is less accurate than triangulated output ('Qt').
Qc
keep coplanar points
Qi
keep interior points
f
facet dump. Print the data structure for each facet.
QVn
select facets containing point n as a vertex,
QGn
select facets that are visible from point n (marked 'good'). Use -n for the remainder.
PDk:0
select facets with a negative coordinate for dimension k
TFn
report progress after constructing n facets
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
Qs
search all points for the initial simplex. If Qhull can not construct an initial simplex, it reports a descriptive message. Usually, the point set is degenerate and one or more dimensions should be removed ('Qbk:0Bk:0'). If not, use option 'Qs'. It performs an exhaustive search for the best initial simplex. This is expensive is high dimensions.

»qconvex graphics

Display 2-d, 3-d, and 4-d convex hulls with Geomview ('G').

Display 2-d and 3-d convex hulls with Mathematica ('m').

To view 4-d convex hulls in 3-d, use 'Pd0d1d2d3' to select the positive octant and 'GrD2' to drop dimension 2.

»qconvex notes

Qhull always computes a convex hull. The convex hull may be used for other geometric structures. The general technique is to transform the structure into an equivalent convex hull problem. For example, the Delaunay triangulation is equivalent to the convex hull of the input sites after lifting the points to a paraboloid.

»qconvex conventions

The following terminology is used for convex hulls in Qhull. See Qhull's data structures.

  • point - d coordinates
  • vertex - extreme point of the input set
  • ridge - d-1 vertices between two neighboring facets
  • hyperplane - halfspace defined by a unit normal and offset
  • coplanar point - a nearly incident point to a hyperplane
  • centrum - a point on the hyperplane for testing convexity
  • facet - a facet with vertices, ridges, coplanar points, neighboring facets, and hyperplane
  • simplicial facet - a facet with d vertices, d ridges, and d neighbors
  • non-simplicial facet - a facet with more than d vertices
  • good facet - a facet selected by 'QVn', etc.

»qconvex options

 qconvex- compute the convex hull
     http://www.qhull.org
 
 input (stdin):
     first lines: dimension and number of points (or vice-versa).
     other lines: point coordinates, best if one point per line
     comments:    start with a non-numeric character
 
 options:
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Qc   - keep coplanar points with nearest facet
     Qi   - keep interior points with nearest facet
 
 Qhull control options:
     Qbk:n   - scale coord k so that low bound is n
       QBk:n - scale coord k so that upper bound is n (QBk is 0.5)
     QbB  - scale input to unit cube centered at the origin
     Qbk:0Bk:0 - remove k-th coordinate from input
     QJn  - randomly joggle input in range [-n,n]
     QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
     Qs   - search all points for the initial simplex
     QGn  - good facet if visible from point n, -n for not visible
     QVn  - good facet if it includes point n, -n if not
 
 Trace options:
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
     Tc   - check frequently during execution
     Ts   - print statistics
     Tv   - verify result: structure, convexity, and point inclusion
     Tz   - send all output to stdout
     TFn  - report summary when n or more facets created
     TI file - input data from file, no spaces or single quotes
     TO file - output results to file, may be enclosed in single quotes
     TPn  - turn on tracing when point n added to hull
      TMn - turn on tracing at merge n
      TWn - trace merge facets when width > n
     TVn  - stop qhull after adding point n, -n for before (see TCn)
      TCn - stop qhull after building cone for point n (see TVn)
 
 Precision options:
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
     Rn   - randomly perturb computations by a factor of [1-n,1+n]
     Un   - max distance below plane for a new, coplanar point
     Wn   - min facet width for outside point (before roundoff)
 
 Output formats (may be combined; if none, produces a summary to stdout):
     f    - facet dump
     G    - Geomview output (see below)
     i    - vertices incident to each facet
     m    - Mathematica output (2-d and 3-d)
     n    - normals with offsets
     o    - OFF file format (dim, points and facets; Voronoi regions)
     p    - point coordinates
     s    - summary (stderr)
 
 More formats:
     Fa   - area for each facet
     FA   - compute total area and volume for option 's'
     Fc   - count plus coplanar points for each facet
            use 'Qc' (default) for coplanar and 'Qi' for interior
     FC   - centrum for each facet
     Fd   - use cdd format for input (homogeneous with offset first)
     FD   - use cdd format for numeric output (offset first)
     FF   - facet dump without ridges
     Fi   - inner plane for each facet
     FI   - ID for each facet
     Fm   - merge count for each facet (511 max)
     FM   - Maple output (2-d and 3-d)
     Fn   - count plus neighboring facets for each facet
     FN   - count plus neighboring facets for each point
     Fo   - outer plane (or max_outside) for each facet
     FO   - options and precision constants
     FP   - nearest vertex for each coplanar point
     FQ   - command used for qconvex
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                       for output: #vertices, #facets,
                                   #coplanar points, #non-simplicial facets
                     #real (2), max outer plane, min vertex
     FS   - sizes:   #int (0)
                     #real(2) tot area, tot volume
     Ft   - triangulation with centrums for non-simplicial facets (OFF format)
     Fv   - count plus vertices for each facet
     FV   - average of vertices (a feasible point for 'H')
     Fx   - extreme points (in order for 2-d)
 
 Geomview output (2-d, 3-d, and 4-d)
     Ga   - all points as dots
      Gp  -  coplanar points and vertices as radii
      Gv  -  vertices as spheres
     Gi   - inner planes only
      Gn  -  no planes
      Go  -  outer planes only
     Gc   - centrums
     Gh   - hyperplane intersections
     Gr   - ridges
     GDn  - drop dimension n in 3-d and 4-d output
 
 Print options:
     PAn  - keep n largest facets by area
     Pdk:n - drop facet if normal[k] <= n (default 0.0)
     PDk:n - drop facet if normal[k] >= n
     Pg   - print good facets (needs 'QGn' or 'QVn')
     PFn  - keep facets whose area is at least n
     PG   - print neighbors of good facets
     PMn  - keep n facets with most merges
     Po   - force output.  If error, output neighborhood of facet
     Pp   - do not report precision problems
 
     .    - list of all options
     -    - one line descriptions of all options
 
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qdelau_f.htm b/html/qdelau_f.htm index 77b5e40..a66fc3a 100644 --- a/html/qdelau_f.htm +++ b/html/qdelau_f.htm @@ -1,414 +1,414 @@ qdelaunay Qu -- furthest-site Delaunay triangulation Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[delaunay]qdelaunay Qu -- furthest-site Delaunay triangulation

The furthest-site Delaunay triangulation corresponds to the upper facets of the Delaunay construction. Its vertices are the extreme points of the input sites. It is the dual of the furthest-site Voronoi diagram.

Example: rbox 10 D2 | qdelaunay Qu Qt s i TO result
Compute the 2-d, furthest-site Delaunay triangulation of 10 random points. Triangulate the output. Write a summary to the console and the regions to 'result'.
 
Example: rbox 10 D2 | qdelaunay Qu QJ s i TO result
Compute the 2-d, furthest-site Delaunay triangulation of 10 random points. Joggle the input to guarantee triangular output. Write a summary to the console and the regions to 'result'.
 
Example: rbox r y c G1 D2 | qdelaunay Qu s Fv TO result
Compute the 2-d, furthest-site Delaunay triangulation of a triangle inside a square. Write a summary to the console and unoriented regions to 'result'. Merge regions for cocircular input sites (e.g., the square). The square is the only furthest-site Delaunay region.

As with the Delaunay triangulation, Qhull computes the furthest-site Delaunay triangulation by lifting the input sites to a paraboloid. The lower facets correspond to the Delaunay triangulation while the upper facets correspond to the furthest-site triangulation. Neither triangulation includes "vertical" facets (i.e., facets whose last hyperplane coefficient is nearly zero). Vertical facets correspond to input sites that are coplanar to the convex hull of the input. An example is points on the boundary of a lattice.

By default, qdelaunay merges cocircular and cospherical regions. For example, the furthest-site Delaunay triangulation of a square inside a diamond ('rbox D2 c d G4 | qdelaunay Qu') consists of one region (the diamond).

If you use 'Qt' (triangulated output), all furthest-site Delaunay regions will be simplicial (e.g., triangles in 2-d). Some regions may be degenerate and have zero area.

If you use 'QJ' (joggled input), all furthest-site Delaunay regions will be simplicial (e.g., triangles in 2-d). Joggled input is less accurate than triangulated output ('Qt'). See Merged facets or joggled input.

The output for 3-d, furthest-site Delaunay triangulations may be confusing if the input contains cospherical data. See the FAQ item Why are there extra points in a 4-d or higher convex hull? Avoid these problems with triangulated output ('Qt') or joggled input ('QJ').

The 'qdelaunay' program is equivalent to 'qhull d Qbb' in 2-d to 3-d, and 'qhull d Qbb Qx' in 4-d and higher. It disables the following Qhull options: d n v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V FC Fi Fo Fp FV Q0,etc. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»furthest-site qdelaunay synopsis

See qdelaunay synopsis. The same program is used for both constructions. Use option 'Qu' for furthest-site Delaunay triangulations.

»furthest-site qdelaunay input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

Use I/O redirection (e.g., qdelaunay Qu < data.txt), a pipe (e.g., rbox 10 | qdelaunay Qu), or the 'TI' option (e.g., qdelaunay Qu TI data.txt).

For example, this is a square containing four random points. Its furthest-site Delaunay triangulation contains one square.

rbox c 4 D2 > data
 2 RBOX c 4 D2
 8
 -0.4999921736307369 -0.3684622117955817
 0.2556053225468894 -0.0413498678629751
 0.0327672376602583 -0.2810408135699488
 -0.452955383763607 0.17886471718444
   -0.5   -0.5
   -0.5    0.5
    0.5   -0.5
    0.5    0.5
 

qdelaunay Qu i < data

 
 Furthest-site Delaunay triangulation by the convex hull of 8 points in 3-d:
 
   Number of input sites: 8
   Number of Delaunay regions: 1
   Number of non-simplicial Delaunay regions: 1
 
 Statistics for: RBOX c 4 D2 | QDELAUNAY s Qu i
 
   Number of points processed: 8
   Number of hyperplanes created: 20
   Number of facets in hull: 11
   Number of distance tests for qhull: 34
   Number of merged facets: 1
   Number of distance tests for merging: 107
   CPU seconds to compute hull (after input): 0.02
 
 1
 7 6 4 5
 

»furthest-site qdelaunay outputs

These options control the output of furthest-site Delaunay triangulations:

furthest-site Delaunay regions
i
list input sites for each furthest-site Delaunay region. The first line is the number of regions. The remaining lines list the input sites for each region. The regions are oriented. In 3-d and higher, report cospherical sites by adding extra points. For the points-in-square example, the square is the only furthest-site Delaunay region.
Fv
list input sites for each furthest-site Delaunay region. The first line is the number of regions. Each remaining line starts with the number of input sites. The regions are unoriented. For the points-in-square example, the square is the only furthest-site Delaunay region.
Ft
print a triangulation of the furthest-site Delaunay regions in OFF format. The first line is the dimension. The second line is the number of input sites and added points, followed by the number of simplices and the number of ridges. The input coordinates are next, followed by the centrum coordinates. There is one centrum for each non-simplicial furthest-site Delaunay region. Each remaining line starts with dimension+1. The simplices are oriented. For the points-in-square example, the square has a centrum at the origin. It splits the square into four triangular regions.
Fn
list neighboring regions for each furthest-site Delaunay region. The first line is the number of regions. Each remaining line starts with the number of neighboring regions. Negative indices (e.g., -1) indicate regions outside of the furthest-site Delaunay triangulation. For the points-in-square example, the four neighboring regions are outside of the triangulation. They belong to the regular Delaunay triangulation.
FN
list the furthest-site Delaunay regions for each input site. The first line is the total number of input sites. Each remaining line starts with the number of furthest-site Delaunay regions. Negative indices (e.g., -1) indicate regions outside of the furthest-site Delaunay triangulation. For the points-in-square example, the four random points belong to no region while the square's vertices belong to region 0 and three regions outside of the furthest-site Delaunay triangulation.
Fa
print area for each furthest-site Delaunay region. The first line is the number of regions. The areas follow, one line per region. For the points-in-square example, the square has unit area.
 
 
Input sites
Fx
list extreme points of the input sites. These points are vertices of the furthest-point Delaunay triangulation. They are on the boundary of the convex hull. The first line is the number of extreme points. Each point is listed, one per line. The points-in-square example has four extreme points.
 
 
General
FA
compute total area for 's' and 'FS'. This is the same as the area of the convex hull.
o
print upper facets of the corresponding convex hull (a paraboloid)
m
Mathematica output for the upper facets of the paraboloid (2-d triangulations).
FM
Maple output for the upper facets of the paraboloid (2-d triangulations).
G
Geomview output for the paraboloid (2-d or 3-d triangulations).
s
print summary for the furthest-site Delaunay triangulation. Use 'Fs' and 'FS' for numeric data.

»furthest-site qdelaunay controls

These options provide additional control:

Qu
must be used for furthest-site Delaunay triangulation.
Qt
triangulated output. Qhull triangulates non-simplicial facets. It may produce degenerate facets of zero area.
QJ
joggle the input to avoid cospherical and coincident sites. It is less accurate than triangulated output ('Qt').
QVn
select facets adjacent to input site n (marked 'good').
Tv
verify result.
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
TFn
report progress after constructing n facets
PDk:1
include upper and lower facets in the output. Set k to the last dimension (e.g., 'PD2:1' for 2-d inputs).
f
facet dump. Print the data structure for each facet (i.e., furthest-site Delaunay region).

»furthest-site qdelaunay graphics

See Delaunay graphics. They are the same except for Mathematica and Maple output.

»furthest-site qdelaunay notes

The furthest-site Delaunay triangulation does not record coincident input sites. Use qdelaunay instead.

qdelaunay Qu does not work for purely cocircular or cospherical points (e.g., rbox c | qdelaunay Qu). Instead, use qdelaunay Qz -- when all points are vertices of the convex hull of the input sites, the Delaunay triangulation is the same as the furthest-site Delaunay triangulation.

A non-simplicial, furthest-site Delaunay region indicates nearly cocircular or cospherical input sites. To avoid non-simplicial regions triangulate the output ('Qt') or joggle the input ('QJ'). Joggled input is less accurate than triangulated output. You may also triangulate non-simplicial regions with option 'Ft'. It adds the centrum to non-simplicial regions. Alternatively, use an exact arithmetic code.

Furthest-site Delaunay triangulations do not include facets that are coplanar with the convex hull of the input sites. A facet is coplanar if the last coefficient of its normal is nearly zero (see qh_ZEROdelaunay).

»furthest-site qdelaunay conventions

The following terminology is used for furthest-site Delaunay triangulations in Qhull. The underlying structure is the upper facets of a convex hull in one higher dimension. See convex hull conventions, Delaunay conventions, and Qhull's data structures

  • input site - a point in the input (one dimension lower than a point on the convex hull)
  • point - d+1 coordinates. The last coordinate is the sum of the squares of the input site's coordinates
  • vertex - a point on the paraboloid. It corresponds to a unique input site.
  • furthest-site Delaunay facet - an upper facet of the paraboloid. The last coefficient of its normal is clearly positive.
  • furthest-site Delaunay region - a furthest-site Delaunay facet projected to the input sites
  • non-simplicial facet - more than d points are cocircular or cospherical
  • good facet - a furthest-site Delaunay facet with optional restrictions by 'QVn', etc.

»furthest-site qdelaunay options

See qdelaunay options. The same program is used for both constructions. Use option 'Qu' for furthest-site Delaunay triangulations.

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qdelaun.htm b/html/qdelaun.htm index 246d29e..9f68eae 100644 --- a/html/qdelaun.htm +++ b/html/qdelaun.htm @@ -1,626 +1,626 @@ qdelaunay -- Delaunay triangulation Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[delaunay]qdelaunay -- Delaunay triangulation

The Delaunay triangulation is the triangulation with empty circumspheres. It has many useful properties and applications. See the survey article by Aurenhammer ['91] and the detailed introduction by O'Rourke ['94].

Example: rbox r y c G0.1 D2 | qdelaunay s Fv TO result
Compute the 2-d Delaunay triangulation of a triangle and a small square. Write a summary to the console and unoriented regions to 'result'. Merge regions for cocircular input sites (i.e., the square).
 
Example: rbox r y c G0.1 D2 | qdelaunay s Fv Qt
Compute the 2-d Delaunay triangulation of a triangle and a small square. Write a summary and unoriented regions to the console. Produce triangulated output.
 
Example: rbox 10 D2 | qdelaunay QJ s i TO result
Compute the 2-d Delaunay triangulation of 10 random points. Joggle the input to guarantee triangular output. Write a summary to the console and the regions to 'result'.

Qhull computes the Delaunay triangulation by computing a convex hull. It lifts the input sites to a paraboloid by adding the sum of the squares of the coordinates. It scales the height of the paraboloid to improve numeric precision ('Qbb'). It computes the convex hull of the lifted sites, and projects the lower convex hull to the input.

Each region of the Delaunay triangulation corresponds to a facet of the lower half of the convex hull. Facets of the upper half of the convex hull correspond to the furthest-site Delaunay triangulation. See the examples, Delaunay and Voronoi diagrams.

See Qhull FAQ - Delaunay and Voronoi diagram questions.

By default, qdelaunay merges cocircular and cospherical regions. For example, the Delaunay triangulation of a square inside a diamond ('rbox D2 c d G4 | qdelaunay') contains one region for the square.

Use option 'Qz' if the input is circular, cospherical, or nearly so. It improves precision by adding a point "at infinity," above the corresponding paraboloid.

If you use 'Qt' (triangulated output), all Delaunay regions will be simplicial (e.g., triangles in 2-d). Some regions may be degenerate and have zero area. Triangulated output identifies coincident points.

If you use 'QJ' (joggled input), all Delaunay regions will be simplicial (e.g., triangles in 2-d). Coincident points will create small regions since the points are joggled apart. Joggled input is less accurate than triangulated output ('Qt'). See Merged facets or joggled input.

The output for 3-d Delaunay triangulations may be confusing if the input contains cospherical data. See the FAQ item Why are there extra points in a 4-d or higher convex hull? Avoid these problems with triangulated output ('Qt') or joggled input ('QJ').

The 'qdelaunay' program is equivalent to 'qhull d Qbb' in 2-d to 3-d, and 'qhull d Qbb Qx' in 4-d and higher. It disables the following Qhull options: d n v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V FC Fi Fo Fp Ft FV Q0,etc. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»qdelaunay synopsis

 qdelaunay- compute the Delaunay triangulation.
     input (stdin): dimension, number of points, point coordinates
     comments start with a non-numeric character
 
 options (qdelaun.htm):
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Qu   - furthest-site Delaunay triangulation
     Tv   - verify result: structure, convexity, and in-circle test
     .    - concise list of all options
     -    - one-line description of all options
 
 output options (subset):
     s    - summary of results (default)
     i    - vertices incident to each Delaunay region
     Fx   - extreme points (vertices of the convex hull)
     o    - OFF format (shows the points lifted to a paraboloid)
     G    - Geomview output (2-d and 3-d points lifted to a paraboloid)
     m    - Mathematica output (2-d inputs lifted to a paraboloid)
     QVn  - print Delaunay regions that include point n, -n if not
     TO file- output results to file, may be enclosed in single quotes
 
 examples:
     rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i
     rbox c P0 D3 | qdelaunay Fv Qt        rbox c P0 D2 | qdelaunay s Qu Fv
     rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay s i Qt
     rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt
 

»qdelaunay input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

Use I/O redirection (e.g., qdelaunay < data.txt), a pipe (e.g., rbox 10 | qdelaunay), or the 'TI' option (e.g., qdelaunay TI data.txt).

For example, this is four cocircular points inside a square. Its Delaunay triangulation contains 8 triangles and one four-sided figure.

rbox s 4 W0 c G1 D2 > data
 2 RBOX s 4 W0 c D2
 8
 -0.4941988586954018 -0.07594397977563715
 -0.06448037284989526 0.4958248496365813
 0.4911154367094632 0.09383830681375946
 -0.348353580869097 -0.3586778257652367
     -1     -1
     -1      1
      1     -1
      1      1
 

qdelaunay s i < data

 
 Delaunay triangulation by the convex hull of 8 points in 3-d
 
   Number of input sites: 8
   Number of Delaunay regions: 9
   Number of non-simplicial Delaunay regions: 1
 
 Statistics for: RBOX s 4 W0 c D2 | QDELAUNAY s i
 
   Number of points processed: 8
   Number of hyperplanes created: 18
   Number of facets in hull: 10
   Number of distance tests for qhull: 33
   Number of merged facets: 2
   Number of distance tests for merging: 102
   CPU seconds to compute hull (after input): 0.028
 
 9
 1 7 5
 6 3 4
 2 3 6
 7 2 6
 2 7 1
 0 5 4
 3 0 4
 0 1 5
 1 0 3 2
 

»qdelaunay outputs

These options control the output of Delaunay triangulations:

Delaunay regions
i
list input sites for each Delaunay region. The first line is the number of regions. The remaining lines list the input sites for each region. The regions are oriented. In 3-d and higher, report cospherical sites by adding extra points. Use triangulated output ('Qt') to avoid non-simpicial regions. For the circle-in-square example, eight Delaunay regions are triangular and the ninth has four input sites.
Fv
list input sites for each Delaunay region. The first line is the number of regions. Each remaining line starts with the number of input sites. The regions are unoriented. For the circle-in-square example, eight Delaunay regions are triangular and the ninth has four input sites.
Fn
list neighboring regions for each Delaunay region. The first line is the number of regions. Each remaining line starts with the number of neighboring regions. Negative indices (e.g., -1) indicate regions outside of the Delaunay triangulation. For the circle-in-square example, the four regions on the square are neighbors to the region-at-infinity.
FN
list the Delaunay regions for each input site. The first line is the total number of input sites. Each remaining line starts with the number of Delaunay regions. Negative indices (e.g., -1) indicate regions outside of the Delaunay triangulation. For the circle-in-square example, each point on the circle belongs to four Delaunay regions. Use 'Qc FN' to include coincident input sites and deleted vertices.
Fa
print area for each Delaunay region. The first line is the number of regions. The areas follow, one line per region. For the circle-in-square example, the cocircular region has area 0.4.
 
 
Input sites
Fc
list coincident input sites for each Delaunay region. The first line is the number of regions. The remaining lines start with the number of coincident sites and deleted vertices. Deleted vertices indicate highly degenerate input (see'Fs'). A coincident site is assigned to one Delaunay region. Do not use 'QJ' with 'Fc'; the joggle will separate coincident sites.
FP
print coincident input sites with distance to nearest site (i.e., vertex). The first line is the number of coincident sites. Each remaining line starts with the point ID of an input site, followed by the point ID of a coincident point, its region, and distance. Includes deleted vertices which indicate highly degenerate input (see'Fs'). Do not use 'QJ' with 'FP'; the joggle will separate coincident sites.
Fx
list extreme points of the input sites. These points are on the boundary of the convex hull. The first line is the number of extreme points. Each point is listed, one per line. The circle-in-square example has four extreme points.
 
 
General
FA
compute total area for 's' and 'FS'
o
print lower facets of the corresponding convex hull (a paraboloid)
m
Mathematica output for the lower facets of the paraboloid (2-d triangulations).
FM
Maple output for the lower facets of the paraboloid (2-d triangulations).
G
Geomview output for the paraboloid (2-d or 3-d triangulations).
s
print summary for the Delaunay triangulation. Use 'Fs' and 'FS' for numeric data.

»qdelaunay controls

These options provide additional control:

Qt
triangulated output. Qhull triangulates non-simplicial facets. It may produce degenerate facets of zero area.
QJ
joggle the input to avoid cospherical and coincident sites. It is less accurate than triangulated output ('Qt').
Qu
compute the furthest-site Delaunay triangulation.
Qz
add a point above the paraboloid to reduce precision errors. Use it for nearly cocircular/cospherical input (e.g., 'rbox c | qdelaunay Qz'). The point is printed for options 'Ft' and 'o'.
QVn
select facets adjacent to input site n (marked 'good').
Tv
verify result.
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
TFn
report progress after constructing n facets
PDk:1
include upper and lower facets in the output. Set k to the last dimension (e.g., 'PD2:1' for 2-d inputs).
f
facet dump. Print the data structure for each facet (i.e., Delaunay region).

»qdelaunay graphics

For 2-d and 3-d Delaunay triangulations, Geomview ('qdelaunay G') displays the corresponding convex hull (a paraboloid).

To view a 2-d Delaunay triangulation, use 'qdelaunay GrD2' to drop the last dimension. This is the same as viewing the hull without perspective (see Geomview's 'cameras' menu).

To view a 3-d Delaunay triangulation, use 'qdelaunay GrD3' to drop the last dimension. You may see extra edges. These are interior edges that Geomview moves towards the viewer (see 'lines closer' in Geomview's camera options). Use option 'Gt' to make the outer ridges transparent in 3-d. See Delaunay and Voronoi examples.

For 2-d Delaunay triangulations, Mathematica ('m') and Maple ('FM') output displays the lower facets of the corresponding convex hull (a paraboloid).

For 2-d, furthest-site Delaunay triangulations, Maple and Mathematica output ('Qu m') displays the upper facets of the corresponding convex hull (a paraboloid).

»qdelaunay notes

You can simplify the Delaunay triangulation by enclosing the input sites in a large square or cube. This is particularly recommended for cocircular or cospherical input data.

A non-simplicial Delaunay region indicates nearly cocircular or cospherical input sites. To avoid non-simplicial regions either triangulate the output ('Qt') or joggle the input ('QJ'). Triangulated output is more accurate than joggled input. Alternatively, use an exact arithmetic code.

Delaunay triangulations do not include facets that are coplanar with the convex hull of the input sites. A facet is coplanar if the last coefficient of its normal is nearly zero (see qh_ZEROdelaunay).

See Imprecision issues :: Delaunay triangulations for a discussion of precision issues. Deleted vertices indicate highly degenerate input. They are listed in the summary output and option 'Fs'.

To compute the Delaunay triangulation of points on a sphere, compute their convex hull. If the sphere is the unit sphere at the origin, the facet normals are the Voronoi vertices of the input. The points may be restricted to a hemisphere. [S. Fortune]

The 3-d Delaunay triangulation of regular points on a half spiral (e.g., 'rbox 100 l | qdelaunay') has quadratic size, while the Delaunay triangulation of random 3-d points is approximately linear for reasonably sized point sets.

With the Qhull library, you can use qh_findbestfacet in poly2.c to locate the facet that contains a point. You should first lift the point to the paraboloid (i.e., the last coordinate is the sum of the squares of the point's coordinates -- qh_setdelaunay). Do not use options 'Qbb', 'QbB', 'Qbk:n', or 'QBk:n' since these scale the last coordinate.

If a point is interior to the convex hull of the input set, it is interior to the adjacent vertices of the Delaunay triangulation. This is demonstrated by the following pipe for point 0:

     qdelaunay <data s FQ QV0 p | qconvex s Qb3:0B3:0 p
 

The first call to qdelaunay returns the neighboring points of point 0 in the Delaunay triangulation. The second call to qconvex returns the vertices of the convex hull of these points (after dropping the lifted coordinate). If point 0 is interior to the original point set, it is interior to the reduced point set.

»qdelaunay conventions

The following terminology is used for Delaunay triangulations in Qhull for dimension d. The underlying structure is the lower facets of a convex hull in dimension d+1. For further information, see data structures and convex hull conventions.

  • input site - a point in the input (one dimension lower than a point on the convex hull)
  • point - a point has d+1 coordinates. The last coordinate is the sum of the squares of the input site's coordinates
  • coplanar point - a coincident input site or a deleted vertex. Deleted vertices indicate highly degenerate input.
  • vertex - a point on the paraboloid. It corresponds to a unique input site.
  • point-at-infinity - a point added above the paraboloid by option 'Qz'
  • lower facet - a facet corresponding to a Delaunay region. The last coefficient of its normal is clearly negative.
  • upper facet - a facet corresponding to a furthest-site Delaunay region. The last coefficient of its normal is clearly positive.
  • Delaunay region - a lower facet projected to the input sites
  • upper Delaunay region - an upper facet projected to the input sites
  • non-simplicial facet - more than d input sites are cocircular or cospherical
  • good facet - a Delaunay region with optional restrictions by 'QVn', etc.

»qdelaunay options

 qdelaunay- compute the Delaunay triangulation
     http://www.qhull.org
 
 input (stdin):
     first lines: dimension and number of points (or vice-versa).
     other lines: point coordinates, best if one point per line
     comments:    start with a non-numeric character
 
 options:
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Qu   - compute furthest-site Delaunay triangulation
 
 Qhull control options:
     QJn  - randomly joggle input in range [-n,n]
     Qs   - search all points for the initial simplex
     Qz   - add point-at-infinity to Delaunay triangulation
     QGn  - print Delaunay region if visible from point n, -n if not
     QVn  - print Delaunay regions that include point n, -n if not
 
 Trace options:
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
     Tc   - check frequently during execution
     Ts   - print statistics
     Tv   - verify result: structure, convexity, and in-circle test
     Tz   - send all output to stdout
     TFn  - report summary when n or more facets created
     TI file - input data from file, no spaces or single quotes
     TO file - output results to file, may be enclosed in single quotes
     TPn  - turn on tracing when point n added to hull
      TMn - turn on tracing at merge n
      TWn - trace merge facets when width > n
     TVn  - stop qhull after adding point n, -n for before (see TCn)
      TCn - stop qhull after building cone for point n (see TVn)
 
 Precision options:
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
     Rn   - randomly perturb computations by a factor of [1-n,1+n]
     Wn   - min facet width for outside point (before roundoff)
 
 Output formats (may be combined; if none, produces a summary to stdout):
     f    - facet dump
     G    - Geomview output (see below)
     i    - vertices incident to each Delaunay region
     m    - Mathematica output (2-d only, lifted to a paraboloid)
     o    - OFF format (dim, points, and facets as a paraboloid)
     p    - point coordinates (lifted to a paraboloid)
     s    - summary (stderr)
 
 More formats:
     Fa   - area for each Delaunay region
     FA   - compute total area for option 's'
     Fc   - count plus coincident points for each Delaunay region
     Fd   - use cdd format for input (homogeneous with offset first)
     FD   - use cdd format for numeric output (offset first)
     FF   - facet dump without ridges
     FI   - ID of each Delaunay region
     Fm   - merge count for each Delaunay region (511 max)
     FM   - Maple output (2-d only, lifted to a paraboloid)
     Fn   - count plus neighboring region for each Delaunay region
     FN   - count plus neighboring region for each point
     FO   - options and precision constants
     FP   - nearest point and distance for each coincident point
     FQ   - command used for qdelaunay
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                     for output: #vertices, #Delaunay regions,
                                 #coincident points, #non-simplicial regions
                     #real (2), max outer plane, min vertex
     FS   - sizes:   #int (0)
                     #real (2), tot area, 0
     Fv   - count plus vertices for each Delaunay region
     Fx   - extreme points of Delaunay triangulation (on convex hull)
 
 Geomview options (2-d and 3-d)
     Ga   - all points as dots
      Gp  -  coplanar points and vertices as radii
      Gv  -  vertices as spheres
     Gi   - inner planes only
      Gn  -  no planes
      Go  -  outer planes only
     Gc     - centrums
     Gh   - hyperplane intersections
     Gr   - ridges
     GDn  - drop dimension n in 3-d and 4-d output
     Gt   - transparent outer ridges to view 3-d Delaunay
 
 Print options:
     PAn  - keep n largest Delaunay regions by area
     Pdk:n - drop facet if normal[k] <= n (default 0.0)
     PDk:n - drop facet if normal[k] >= n
     Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')
     PFn  - keep Delaunay regions whose area is at least n
     PG   - print neighbors of good regions (needs 'QGn' or 'QVn')
     PMn  - keep n Delaunay regions with most merges
     Po   - force output.  If error, output neighborhood of facet
     Pp   - do not report precision problems
 
     .    - list of all options
     -    - one line descriptions of all options
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-code.htm b/html/qh-code.htm index 4141718..f8326c5 100644 --- a/html/qh-code.htm +++ b/html/qh-code.htm @@ -1,954 +1,954 @@ Qhull code

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull code: Table of Contents (please wait while loading)
Dn: Qhull functions, macros, and data structures


[4-d cube] Qhull code

This section discusses the code for Qhull.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»Qhull code: Table of Contents


»Performance of Qhull

Empirically, Qhull's performance is balanced in the sense that the average case happens on average. This may always be true if the precision of the input is limited to at most O(log n) bits. Empirically, the maximum number of vertices occurs at the end of constructing the hull.

Let n be the number of input points, v be the number of output vertices, and f_v be the maximum number of facets for a convex hull of v vertices. If both conditions hold, Qhull runs in O(n log v) in 2-d and 3-d and O(n f_v/v) otherwise. The function f_v increases rapidly with dimension. It is O(v^floor(d/2) / floor(d/2)!).

The time complexity for merging is unknown. Options 'C-0' and 'Qx' (defaults) handle precision problems due to floating-point arithmetic. They are optimized for simplicial outputs.

When running large data sets, you should monitor Qhull's performance with the 'TFn' option. The time per facet is approximately constant. In high-d with many merged facets, the size of the ridge sets grows rapidly. For example the product of 8-d simplices contains 18 facets and 500,000 ridges. This will increase the time needed per facet.

As dimension increases, the number of facets and ridges in a convex hull grows rapidly for the same number of vertices. For example, the convex hull of 300 cospherical points in 6-d has 30,000 facets.

If Qhull appears to stop processing facets, check the memory usage of Qhull. If more than 5-10% of Qhull is in virtual memory, its performance will degrade rapidly.

When building hulls in 20-d and higher, you can follow the progress of Qhull with option 'T1'. It reports each major event in processing a point.

To reduce memory requirements, recompile Qhull for single-precision reals (REALfloat in user.h). Single-precision does not work with joggle ('QJ'). Check qh_MEMalign in user.h and the match between free list sizes and data structure sizes (see the end of the statistics report from 'Ts'). If free list sizes do not match, you may be able to use a smaller qh_MEMalign. Setting qh_COMPUTEfurthest saves a small amount of memory, as does clearing qh_MAXoutside (both in user.h).

Shewchuk is working on a 3-d version of his triangle program. It is optimized for 3-d simplicial Delaunay triangulation and uses less memory than Qhull.

To reduce the size of the Qhull executable, consider qh_NOtrace and qh_KEEPstatistics 0 in user.h. By changing user.c you can also remove the input/output code in io.c. If you don't need facet merging, then version 1.01 of Qhull is much smaller. It contains some bugs that prevent Qhull from initializing in simple test cases. It is slower in high dimensions.

The precision options, 'Vn', 'Wn', 'Un'. 'A-n', 'C-n', 'An', 'Cn', and 'Qx', may have large effects on Qhull performance. You will need to experiment to find the best combination for your application.

The verify option ('Tv') checks every point after the hull is complete. If facet merging is used, it checks that every point is inside every facet. This can take a very long time if there are many points and many facets. You can interrupt the verify without losing your output. If facet merging is not used and there are many points and facets, Qhull uses a directed search instead of an exhaustive search. This should be fast enough for most point sets. Directed search is not used for facet merging because directed search was already used for updating the facets' outer planes.

The check-frequently option ('Tc') becomes expensive as the dimension increases. The verify option ('Tv') performs many of the same checks before outputting the results.

Options 'Q0' (no pre-merging), 'Q3' (no checks for redundant vertices), 'Q5' (no updates for outer planes), and 'Q8' (no near-interior points) increase Qhull's speed. The corresponding operations may not be needed in your application.

In 2-d and 3-d, a partial hull may be faster to produce. Option 'QgGn' only builds facets visible to point n. Option 'QgVn' only builds facets that contain point n. In higher-dimensions, this does not reduce the number of facets.

User.h includes a number of performance-related constants. Changes may improve Qhull performance on your data sets. To understand their effect on performance, you will need to read the corresponding code.

GNU gprof reports that the dominate cost for 3-d convex hull of cosperical points is qh_distplane(), mainly called from qh_findbestnew(). The dominate cost for 3-d Delaunay triangulation is creating new facets in qh_addpoint(), while qh_distplane() remains the most expensive function.

»Calling Qhull from C++ programs

Warning: The C++ interface to Qhull is new and incomplete. You will need to extend the interface for all but the simplest applications. You will need to understand the data structures and read the code. Most users will find it easier to call Qhull as a program.

Note: Please download the 'next' branch from git://gitorious.org/qhull/qhull.git

Qhull's C++ interface provides wrapper classes for Qhull and Rbox. It provides access to Qhull's data structures. Most of the classes derive from the corresponding qhull data structure. For example, QhullFacet is an instance of Qhull's facetT.

The main methods are
  • RboxPoints.appendRandomPoints -- append random points according to rbox options.
  • Qhull.runQhull -- construct the convex hull of the input points
  • Qhull.outputQhull -- write output according to Qhull options
The sample program, user_eg3.cpp, duplicates Qhull's facet dump (option 'f'). Example (c.f., user_eg3 eg-100)
     RboxPoints rbox;
     rbox.appendRandomPoints("100");
     Qhull qhull;
     qhull.runQhull("", rbox);
     QhullFacetList facets(qhull);
     cout<< facets;
 

The C++ iterface for RboxPoints redefines the fprintf() calls in rboxlib.c. Instead of writing its output to stdout, RboxPoints appends the output to a std::vector. The same technique may be used for calling Qhull from C++.

  • Run Qhull with option 'Ta' to annotate the output with qh_fprintf() identifiers.
  • Redefine qh_fprintf() for these identifiers.
  • See RboxPoints.cpp for an example.

A more flexible approach extends Qhull's classes. For example, to access the vertices of a QhullFacet, define a constructor of QhullVertexSet that takes a QhullFacet as a parameter.

With care, you may create multiple Qhull instances, but only one thread may use qh_qh, qh_qhstat, and qhmem at a time (i.e., most of libqhull, the original C program). only one instance may be active at time. The global pointer qh_qh points to Qhull's data structure, QhullQh. The class UsingLibQhull checks that qh_qh is correct.

Qhull objects have the entire qhull data structure, so they can explore this data structure independent of libqhull. You can use any method that does not refer to UsingLibQhull, or invoke methods that refer to UsingLibQhull. You may also use any method in libqhull that does not reference qh_qh, qh_qhstat (i.e., does not include the macro 'qh', zinc_, etc) and does not allocate or deallocate memory via mem.c. In particular, you can call most of the qset macros and functions, allowing you to explore the data structure with 'foreachFacet_(), etc.' You can call all of the qset.h functions if you turn off Qhull's memory manager (qh_NOmem in mem.h)

»Cpp questions for Qhull

Developing C++ code requires many conventions, idioms, and technical details. The following questions have either mystified the author or do not have a clear answer. See also C++ and Perl Guidelines, C++ interface to Qhull. and FIXUP in the code. Please add notes to Gitorious wiki.
  • FIXUP QH11026 Should return reference, but get reference to temporary
    iterator Coordinates::operator++() { return iterator(++i); }
  • size() as size_t, size_type, or int
  • Should all containers have a reserve()?
  • Qhull.feasiblePoint interface
  • How to avoid copy constructor while logging, maybeThrowQhullMessage()
  • How to configure Qhull output. Trace and results should go to stdout/stderr
  • Qhull and RboxPoints messaging. e.g., ~Qhull, hasQhullMessage(). Rename them as QhullErrorMessage?
  • How to add additional output to an error message, e.g., qh_setprint
  • Is idx the best name for an index? It's rather cryptic, but BSD strings.h defines index().
  • Qhull::feasiblePoint Qhull::useOutputStream as field or getter?
  • Define virtual functions for user customization of Qhull (e.g., qh_fprintf, qh_memfree,etc.)
  • Figure out RoadError::global_log. clearQhullMessage currently clearGlobalLog
  • Should the false QhullFacet be NULL or empty? e.g., QhullFacet::tricoplanarOwner() and QhullFacetSet::end()
  • Should output format for floats be predefined (qh_REAL_1, 2.2g, 10.7g) or as currently set for stream
  • Should cout << !point.defined() be blank or 'undefined'
  • Interface for UsingLibQhull::globalAngleEpsilon(), globalDistanceEpsilon, etc.
  • Interface for UsingLibQhull::globalDimension
  • Set up globals for thread-private storage (redefine macros qh, qhstat, etc)
  • Is Q_GLOBAL_STATIC non-threaded/threaded, needed for Qhull?
  • Infinite point as !defined()
  • qlist and qlinkedlist define pointer, reference, size_type, difference_type, const_pointer, const_reference for the class but not for iterator and const_iterator vector.h --
    reference operator[](difference_type _Off) const
  • When forwarding an implementation is base() an approriate name (e.g., Coordinates::iterator::base() as std::vector::iterator).
  • When forwarding an implementation, does not work "returning address of temporary"
  • Also --, +=, and -=
    iterator       &operator++() { return iterator(i++); }
  • if vector inheritance is bad, is QhullVertexSet OK?
  • Should QhullPointSet define pointer and reference data types?
  • Allow UsingQhullLib to work with static allocation of qh_qh

»CoordinateIterator

A CoordinateIterator or ConstCoordinateIterator [RboxPoints.cpp] is a std::vector<realT>::iterator for Rbox and Qhull coordinates. It is the result type of RboxPoints.coordinates().

Qhull does not use CoordinateIterator for its data structures. A point in Qhull is an array of reals instead of a std::vector. See QhullPoint.

»Qhull

Qhull is the top-level class for running Qhull. It initializes Qhull, runs the computation, and records errors. It provides access to the global data structure QhullQh, Qhull's facets, and vertices.

»QhullError

QhullError is derived from std::exception. It reports errors from Qhull and captures the output to stderr.

If error handling is not set up, Qhull exits with a code from 1 to 5 [qh_ERR* in libqhull.h via qh_exit() in usermem.c]. The C++ interface does not report the captured output in QhullError. Call Qhull::setErrorStream to send output to cerr instead.

»QhullFacet

A QhullFacet is a facet of the convex hull, a region of the Delaunay triangulation, a vertex of a Voronoi diagram, or an intersection of the halfspace intersection about a point. A QhullFacet has a set of QhullVertex, a set of QhullRidge, and a set of neighboring QhullFacets.

»QhullFacetList

A QhullFacetList is a linked list of QhullFacet. The result of Qhull.runQhull is a QhullFacetList stored in QhullQh.

»QhullFacetSet

A QhullFacetSet is a QhullSet of QhullFacet. QhullFacetSet may be ordered or unordered. The neighboring facets of a QhullFacet is a QhullFacetSet. The neighbors of a QhullFacet is a QhullFacetSet. The neighbors are ordered for simplicial facets, matching the opposite vertex of the facet.

»QhullIterator

QhullIterator contains macros for defining Java-style iterator templates from a STL-style iterator template.

»QhullLinkedList

A QhullLinkedLIst is a template for linked lists with next and previous pointers. QhullFacetList and QhullVertexList are QhullLinkedLists.

»QhullPoint

A QhullPoint is an array of point coordinates, typically doubles. The length of the array is QhullQh.hull_dim. The identifier of a QhullPoint is its 0-based index from QhullQh.first_point followed by QhullQh.other_points.

»QhullPointSet

A QhullPointSet is a QhullSet of QhullPoint. The QhullPointSet of a QhullFacet is its coplanar points.

»QhullQh

QhullQh is the root of Qhull's data structure. It contains initialized constants, sets, buffers, and variables. It contains an array and a set of QhullPoint, a list of QhullFacet, and a list of QhullVertex. The points are the input to Qhull. The facets and vertices are the result of running Qhull.

Qhull's functions access QhullQh through the global variable, qh_qh. The global data structures, qh_stat and qh_mem, record statistics and manage memory respectively.

»QhullRidge

A QhullRidge represents the edge between two QhullFacet's. It is always simplicial with qh.hull_dim-1 QhullVertex)'s.

»QhullRidgeSet

A QhullRidgeSet is a QhullSet of QhullRidge. Each QhullFacet contains a QhullRidgeSet.

»QhullSet

A QhullSet is a set of pointers to objects. QhullSets may be ordered or unordered. They are the core data structure for Qhull.

»QhullVertex

A QhullVertex is a vertex of the convex hull. A simplicial QhullFacet has qh.hull_dim-1 vertices. A QhullVertex contains a QhullPoint. It may list its neighboring QhullFacet's.

»QhullVertexList

A QhullVertexList is a QhullLinkedList of QhullVertex. The global data structure, QhullQh contains a QhullVertexList of all the vertices.

»QhullVertexSet

A QhullVertexSet is a QhullSet of QhullVertex. The QhullVertexSet of a QhullFacet is the vertices of the facet. It is ordered for simplicial facets and unordered for non-simplicial facets.

»RboxPoints

RboxPoints is a std::vector of point coordinates (QhullPoint). It's iterator is CoordinateIterator.

RboxPoints.appendRandomPoints() appends points from a variety of distributions such as uniformly distributed within a cube and random points on a sphere. It can also append a cube's vertices or specific points.

»UsingLibQhull

UsingLibQhull checks that the current thread owns Qhull's global data structure, QhullQh. It is required while calling the Qhull library. Otherwise two threads may be updating and reading the same data structure.

»Calling Qhull from C programs

Warning: Qhull was not designed for calling from C programs. You may find the C++ interface easier to use. You will need to understand the data structures and read the code. Most users will find it easier to call Qhull as an external command.

For examples of calling Qhull, see GNU Octave's computational geometry code, and Qhull's user_eg.c, user_eg2.c, and user.c. To see how Qhull calls its library, read unix.c, qconvex.c, qdelaun.c, qhalf.c, and qvoronoi.c.

The BGL Boost Graph Library [aka GGCL] provides C++ classes for graph data structures and algorithms [Dr. Dobb's 9/00 p. 29-38; OOPSLA '99 p. 399-414]. It is modelled after the Standard Template Library. It would provide a good interface to Qhull. If you are interested in adapting BGL to Qhull, please contact bradb@shore.net.

See Qhull functions, macros, and data structures for internal documentation of Qhull. The documentation provides an overview and index. To use the library you will need to read and understand the code. For most users, it is better to write data to a file, call the qhull program, and read the results from the output file.

When you read the code, be aware of the macros "qh" and "qhstat", e.g., "qh hull_dim". They are defined in libqhull.h. They allow the global data structures to be pre-allocated (faster access) or dynamically allocated (allows multiple copies).

Qhull's Makefile produces a library, libqhull.a, for inclusion in your programs. First review libqhull.h. This defines the data structures used by Qhull and provides prototypes for the top-level functions. Most users will only need libqhull.h in their programs. For example, the Qhull program is defined with libqhull.h and unix.c. To access all functions, use qhull_a.h. Include the file with "#include <libqhull/qhull_a.h>". This avoids potential name conflicts.

If you use the Qhull library, you are on your own as far as bugs go. Start with small examples for which you know the output. If you get a bug, try to duplicate it with the Qhull program. The 'Tc' option will catch many problems as they occur. When an error occurs, use 'T4 TPn' to trace from the last point added to the hull. Compare your trace with the trace output from the Qhull program.

Errors in the Qhull library are more likely than errors in the Qhull program. These are usually due to feature interactions that do not occur in the Qhull program. Please report all errors that you find in the Qhull library. Please include suggestions for improvement.

»sets and quick memory allocation

You can use mem.c and qset.c individually. Mem.c implements quick-fit memory allocation. It is faster than malloc/free in applications that allocate and deallocate lots of memory.

Qset.c implements sets and related collections. It's the inner loop of Qhull, so speed is more important than abstraction. Set iteration is particularly fast. qset.c just includes the functions needed for Qhull.

»Delaunay triangulations and point indices

Here some unchecked code to print the point indices of each Delaunay triangle. Use option 'QJ' if you want to avoid non-simplicial facets. Note that upper Delaunay regions are skipped. These facets correspond to the furthest-site Delaunay triangulation.

   facetT *facet;
   vertexT *vertex, **vertexp;
 
   FORALLfacets {
     if (!facet->upperdelaunay) {
       printf ("%d", qh_setsize (facet->vertices);
       FOREACHvertex_(facet->vertices)
         printf (" %d", qh_pointid (vertex->point));
       printf ("\n");
     }
   }
 
 

»locate a facet with qh_findbestfacet()

The routine qh_findbestfacet in poly2.c is particularly useful. It uses a directed search to locate the facet that is furthest below a point. For Delaunay triangulations, this facet is the Delaunay triangle that contains the lifted point. For convex hulls, the distance of a point to the convex hull is either the distance to this facet or the distance to a subface of the facet.

Warning: If triangulated output ('Qt') and the best facet is triangulated, qh_findbestfacet() returns one of the corresponding 'tricoplanar' facets. The actual best facet may be a different tricoplanar facet.

See qh_nearvertex() in poly2.c for sample code to visit each tricoplanar facet. To identify the correct tricoplanar facet, see Devillers, et. al., ['01] and Mucke, et al ['96]. If you implement this test in general dimension, please notify qhull@qhull.org.

qh_findbestfacet performs an exhaustive search if its directed search returns a facet that is above the point. This occurs when the point is inside the hull or if the curvature of the convex hull is less than the curvature of a sphere centered at the point (e.g., a point near a lens-shaped convex hull). When the later occurs, the distance function is bimodal and a directed search may return a facet on the far side of the convex hull.

Algorithms that retain the previously constructed hulls usually avoid an exhaustive search for the best facet. You may use a hierarchical decomposition of the convex hull [Dobkin and Kirkpatrick '90].

To use qh_findbestfacet with Delaunay triangulations, lift the point to a paraboloid by summing the squares of its coordinates (see qh_setdelaunay in geom2.c). Do not scale the input with options 'Qbk', 'QBk', 'QbB' or 'Qbb'. See Mucke, et al ['96] for a good point location algorithm.

The intersection of a ray with the convex hull may be found by locating the facet closest to a distant point on the ray. Intersecting the ray with the facet's hyperplane gives a new point to test.

»on-line construction with qh_addpoint()

The Qhull library may be used for the on-line construction of convex hulls, Delaunay triangulations, and halfspace intersections about a point. It may be slower than implementations that retain intermediate convex hulls (e.g., Clarkson's hull program). These implementations always use a directed search. For the on-line construction of convex hulls and halfspace intersections, Qhull may use an exhaustive search (qh_findbestfacet).

You may use qh_findbestfacet and qh_addpoint (libqhull.c) to add a point to a convex hull. Do not modify the point's coordinates since qh_addpoint does not make a copy of the coordinates. For Delaunay triangulations, you need to lift the point to a paraboloid by summing the squares of the coordinates (see qh_setdelaunay in geom2.c). Do not scale the input with options 'Qbk', 'QBk', 'QbB' or 'Qbb'. Do not deallocate the point's coordinates. You need to provide a facet that is below the point (qh_findbestfacet).

You can not delete points. Another limitation is that Qhull uses the initial set of points to determine the maximum roundoff error (via the upper and lower bounds for each coordinate).

For many applications, it is better to rebuild the hull from scratch for each new point. This is especially true if the point set is small or if many points are added at a time.

Calling qh_addpoint from your program may be slower than recomputing the convex hull with qh_qhull. This is especially true if the added points are not appended to the qh first_point array. In this case, Qhull must search a set to determine a point's ID. [R. Weber]

See user_eg.c for examples of the on-line construction of convex hulls, Delaunay triangulations, and halfspace intersections. The outline is:

 initialize qhull with an initial set of points
 qh_qhull();
 
 for each additional point p
    append p to the end of the point array or allocate p separately
    lift p to the paraboloid by calling qh_setdelaunay
    facet= qh_findbestfacet (p, !qh_ALL, &bestdist, &isoutside);
    if (isoutside)
       if (!qh_addpoint (point, facet, False))
          break;  /* user requested an early exit with 'TVn' or 'TCn' */
 
 call qh_check_maxout() to compute outer planes
 terminate qhull

»Constrained Delaunay triangulation

With a fair amount of work, Qhull is suitable for constrained Delaunay triangulation. See Shewchuk, ACM Symposium on Computational Geometry, Minneapolis 1998.

Here's a quick way to add a constraint to a Delaunay triangulation: subdivide the constraint into pieces shorter than the minimum feature separation. You will need an independent check of the constraint in the output since the minimum feature separation may be incorrect. [H. Geron]

»Tricoplanar facets and option 'Qt'

Option 'Qt' triangulates non-simplicial facets (e.g., a square facet in 3-d or a cubical facet in 4-d). All facets share the same apex (i.e., the first vertex in facet->vertices). For each triangulated facet, Qhull sets facet->tricoplanar true and copies facet->center, facet->normal, facet->offset, and facet->maxoutside. One of the facets owns facet->normal; its facet->keepcentrum is true. If facet->isarea is false, facet->triowner points to the owning facet.

Qhull sets facet->degenerate if the facet's vertices belong to the same ridge of the non-simplicial facet.

To visit each tricoplanar facet of a non-simplicial facet, either visit all neighbors of the apex or recursively visit all neighbors of a tricoplanar facet. The tricoplanar facets will have the same facet->center.

See qh_detvridge for an example of ignoring tricoplanar facets.

»Voronoi vertices of a region

The following code iterates over all Voronoi vertices for each Voronoi region. Qhull computes Voronoi vertices from the convex hull that corresponds to a Delaunay triangulation. An input site corresponds to a vertex of the convex hull and a Voronoi vertex corresponds to an adjacent facet. A facet is "upperdelaunay" if it corresponds to a Voronoi vertex "at-infinity". Qhull uses qh_printvoronoi in io.c for 'qvoronoi o'

 /* please review this code for correctness */
 qh_setvoronoi_all();
 FORALLvertices {
    site_id = qh_pointid (vertex->point);
    if (qh hull_dim == 3)
       qh_order_vertexneighbors(vertex);
    infinity_seen = 0;
    FOREACHneighbor_(vertex) {
       if (neighbor->upperdelaunay) {
         if (!infinity_seen) {
           infinity_seen = 1;
           ... process a Voronoi vertex "at infinity" ...
         }
       }else {
         voronoi_vertex = neighbor->center;
         ... your code goes here ...
       }
    }
 }
 

»Voronoi vertices of a ridge

Qhull uses qh_printvdiagram() in io.c to print the ridges of a Voronoi diagram for option 'Fv'. The helper function qh_eachvoronoi() does the real work. It calls the callback 'printvridge' for each ridge of the Voronoi diagram.

You may call qh_printvdiagram2(), qh_eachvoronoi(), or qh_eachvoronoi_all() with your own function. If you do not need the total number of ridges, you can skip the first call to qh_printvdiagram2(). See qh_printvridge() and qh_printvnorm() in io.c for examples.

»vertex neighbors of a vertex

To visit all of the vertices that share an edge with a vertex:

  • Generate neighbors for each vertex with qh_vertexneighbors in poly2.c.
  • For simplicial facets, visit the vertices of each neighbor
  • For non-simplicial facets,
    • Generate ridges for neighbors with qh_makeridges in merge.c.
    • Generate ridges for a vertex with qh_vertexridges in merge.c.
    • Visit the vertices of these ridges.

For non-simplicial facets, the ridges form a simplicial decomposition of the (d-2)-faces between each pair of facets -- if you need 1-faces, you probably need to generate the full face graph of the convex hull.

»Enhancements to Qhull

There are many ways in which Qhull can be improved.

 [Jan 2010] Suggestions
  - Generate vcproj from qtpro files
    cd qtpro && qmake -spec win32-msvc2005 -tp vc -recursive
    sed -i 's/C\:\/bash\/local\/qhull\/qtpro\///' qhull-all.sln
    Change qhullcpp to libqhull.dll
    Allow both builds on same host (keep /tmp separate)
  - Make distribution -- remove tmp, news, .git, leftovers from project, change CRLF
      search for 2010.1, Dates
      qhulltest --all added to output
      Add md5sum
      Add test of user_eg3, etc.
  - C++ class for access to statistics, accumulate vs. add
  - Add dialog box to RoadError-- a virtual function?
  - Option 'Gt' does not make visible all facets of the mesh example, rbox 32 M1,0,1 | qhull d Gt
  - Option to select bounded Voronoi regions [A. Uzunovic]
  - Merge small volume boundary cells into unbounded regions [Dominik Szczerba]
  - Postmerge with merge options
  - Add const to C code
  - Add modify operators and MutablePointCoordinateIterator to PointCoordinates
  - Add Qtest::toString() functions for QhullPoint and others.  QByteArray and qstrdup()
  - Fix option Qt for conformant triangulations of merged facets
  - Investigate flipped facet -- rbox 100 s D3 t1263080158 | qhull R1e-3 Tcv Qc
  - Add doc comments to c++ code
  - Measure performance of Qhull, seconds per point by dimension
  - Report potential wraparound of 64-bit ints -- e.g., a large set or points
 
 Documentation
 - Qhull::addPoint().  Problems with qh_findbestfacet and otherpoints see
    qh-code.htm#inc on-line construction with qh_addpoint()
 - How to handle 64-bit possible loss of data.  WARN64, ptr_intT, size_t/int
 - Show custom of qh_fprintf
 - grep 'qh_mem ' x | sort | awk '{ print $2; }' | uniq -c | grep -vE ' (2|4|6|8|10|12|14|16|20|64|162)[^0-9]'
 - qtpro/qhulltest contains .pro and Makefile.  Remove Makefiles by setting shadow directory to ../../tmp/projectname
 - Rules for use of qh_qh and multi processes
     UsingQhull
     errorIfAnotherUser
     ~QhullPoints() needs ownership of qh_qh
     Does !qh_pointer work?
     When is qh_qh required?  Minimize the time.
    qhmem, qhstat.ferr
    qhull_inuse==1 when qhull globals active [not useful?]
    rbox_inuse==1 when rbox globals active
    - Multithreaded -- call largest dimension for infinityPoint() and origin()
  - Better documentation for qhmem totshort, freesize, etc.
  - how to change .h, .c, and .cpp to text/html.  OK in Opera
  - QhullVertex.dimension() is not quite correct, epensive
  - Check globalAngleEpsilon
  - Deprecate save_qhull()
 
 [Dec 2003] Here is a partial list:
  - fix finddelaunay() in user_eg.c for tricoplanar facets
  - write a BGL, C++ interface to Qhull
      http://www.boost.org/libs/graph/doc/table_of_contents.html
  - change qh_save_qhull to swap the qhT structure instead of using pointers
  - change error handling and tracing to be independent of 'qh ferr'
  - determine the maximum width for a given set of parameters
  - prove that directed search locates all coplanar facets
  - in high-d merging, can a loop of facets become disconnected?
  - find a way to improve inner hulls in 5-d and higher
  - determine the best policy for facet visibility ('Vn')
  - determine the limitations of 'Qg'
 
 Precision improvements:
  - For 'Qt', resolve cross-linked, butterfly ridges.
      May allow retriangulation in qh_addpoint().
  - for Delaunay triangulations ('d' or 'v') under joggled input ('QJ'),
      remove vertical facets whose lowest vertex may be coplanar with convex hull
  - review use of 'Qbb' with 'd QJ'.  Is MAXabs_coord better than MAXwidth?
  - check Sugihara and Iri's better in-sphere test [Canadian
      Conf. on Comp. Geo., 1989; Univ. of Tokyo RMI 89-05]
  - replace centrum with center of mass and facet area
  - handle numeric overflow in qh_normalize and elsewhere
  - merge flipped facets into non-flipped neighbors.
      currently they merge into best neighbor (appears ok)
  - determine min norm for Cramer's rule (qh_sethyperplane_det).  It looks high.
  - improve facet width for very narrow distributions
 
 New features:
  - implement Matlab's tsearch() using Qhull
  - compute volume of Voronoi regions.  You need to determine the dual face
    graph in all dimensions [see Clarkson's hull program]
  - compute alpha shapes [see Clarkson's hull program]
  - implement deletion of Delaunay vertices
       see Devillers, ACM Symposium on Computational Geometry, Minneapolis 1999.
  - compute largest empty circle [see O'Rourke, chapter 5.5.3] [Hase]
  - list redundant (i.e., coincident) vertices [Spitz]
  - implement Mucke, et al, ['96] for point location in Delaunay triangulations
  - implement convex hull of moving points
  - implement constrained Delaunay diagrams
       see Shewchuk, ACM Symposium on Computational Geometry, Minneapolis 1998.
  - estimate outer volume of hull
  - automatically determine lower dimensional hulls
  - allow "color" data for input points
       need to insert a coordinate for Delaunay triangulations
 
 Input/output improvements:
  - Support the VTK Visualization Toolkit, http://www.kitware.com/vtk.html
  - generate output data array for Qhull library [Gautier]
  - need improved DOS window with screen fonts, scrollbar, cut/paste
  - generate Geomview output for Voronoi ridges and unbounded rays
  - generate Geomview output for halfspace intersection
  - generate Geomview display of furthest-site Voronoi diagram
  - use 'GDn' to view 5-d facets in 4-d
  - convert Geomview output for other 3-d viewers
  - add interactive output option to avoid recomputing a hull
  - orient vertex neighbors for 'Fv' in 3-d and 2-d
  - track total number of ridges for summary and logging
 
 Performance improvements:
  - optimize Qhull for 2-d Delaunay triangulations
  -   use O'Rourke's '94 vertex->duplicate_edge
  -   add bucketing
  -   better to specialize all of the code (ca. 2-3x faster w/o merging)
  - use updated LU decomposition to speed up hyperplane construction
  -        [Gill et al. 1974, Math. Comp. 28:505-35]
  - construct hyperplanes from the corresponding horizon/visible facets
  - for merging in high d, do not use vertex->neighbors
 
 

Please let us know about your applications and improvements.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull code: Table of Contents
Dn: Qhull functions, macros, and data structures


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see changes.txt

diff --git a/html/qh-eg.htm b/html/qh-eg.htm index 5b42da0..3973276 100644 --- a/html/qh-eg.htm +++ b/html/qh-eg.htm @@ -1,691 +1,691 @@ Examples of Qhull

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull examples: Table of Contents (please wait while loading)


[halfspace] Examples of Qhull

This section of the Qhull manual will introduce you to Qhull and its options. Each example is a file for viewing with Geomview. You will need to use a Unix computer with a copy of Geomview.

If you are not running Unix, you can view pictures for some of the examples. To understand Qhull without Geomview, try the examples in Programs and Programs/input. You can also try small examples that you compute by hand. Use rbox to generate examples.

To generate the Geomview examples, execute the shell script eg/q_eg. It uses rbox. The shell script eg/q_egtest generates test examples, and eg/q_test exercises the code. If you find yourself viewing the inside of a 3-d example, use Geomview's normalization option on the 'obscure' menu.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»Qhull examples: Table of Contents



»2-d and 3-d examples

»rbox c D3 | qconvex G >eg.01.cube

The first example is a cube in 3-d. The color of each facet indicates its normal. For example, normal [0,0,1] along the Z axis is (r=0.5, g=0.5, b=1.0). With the 'Dn' option in rbox, you can generate hypercubes in any dimension. Above 7-d the number of intermediate facets grows rapidly. Use 'TFn' to track qconvex's progress. Note that each facet is a square that qconvex merged from coplanar triangles.

»rbox c d G3.0 | qconvex G >eg.02.diamond.cube

The second example is a cube plus a diamond ('d') scaled by rbox's 'G' option. In higher dimensions, diamonds are much simpler than hypercubes.

»rbox s 100 D3 | qconvex G >eg.03.sphere

The rbox s option generates random points and projects them to the d-sphere. All points should be on the convex hull. Notice that random points look more clustered than you might expect. You can get a smoother distribution by merging facets and printing the vertices, e.g., rbox 1000 s | qconvex A-0.95 p | qconvex G >eg.99.

»rbox s 100 D2 | qconvex G >eg.04.circle

In 2-d, there are many ways to generate a convex hull. One of the earliest algorithms, and one of the fastest, is the 2-d Quickhull algorithm [c.f., Preparata & Shamos '85]. It was the model for Qhull.

»rbox 10 l | qconvex G >eg.05.spiral

One rotation of a spiral.

»rbox 1000 D2 | qconvex C-0.03 Qc Gapcv >eg.06.merge.square

This demonstrates how Qhull handles precision errors. Option 'C-0.03' requires a clearly convex angle between adjacent facets. Otherwise, Qhull merges the facets.

This is the convex hull of random points in a square. The facets have thickness because they must be outside all points and must include their vertices. The colored lines represent the original points and the spheres represent the vertices. Floating in the middle of each facet is the centrum. Each centrum is at least 0.03 below the planes of its neighbors. This guarantees that the facets are convex.

»rbox 1000 D3 | qconvex G >eg.07.box

Here's the same distribution but in 3-d with Qhull handling machine roundoff errors. Note the large number of facets.

»rbox c G0.4 s 500 | qconvex G >eg.08a.cube.sphere

The sphere is just barely poking out of the cube. Try the same distribution with randomization turned on ('Qr'). This turns Qhull into a randomized incremental algorithm. To compare Qhull and randomization, look at the number of hyperplanes created and the number of points partitioned. Don't compare CPU times since Qhull's implementation of randomization is inefficient. The number of hyperplanes and partitionings indicate the dominant costs for Qhull. With randomization, you'll notice that the number of facets created is larger than before. This is especially true as you increase the number of points. It is because the randomized algorithm builds most of the sphere before it adds the cube's vertices.

»rbox d G0.6 s 500 | qconvex G >eg.08b.diamond.sphere

This is a combination of the diamond distribution and the sphere.

»rbox 100 L3 G0.5 s | qconvex G >eg.09.lens

Each half of the lens distribution lies on a sphere of radius three. A directed search for the furthest facet below a point (e.g., qh_findbest in geom.c) may fail if started from an arbitrary facet. For example, if the first facet is on the opposite side of the lens, a directed search will report that the point is inside the convex hull even though it is outside. This problem occurs whenever the curvature of the convex hull is less than a sphere centered at the test point.

To prevent this problem, Qhull does not use directed search all the time. When Qhull processes a point on the edge of the lens, it partitions the remaining points with an exhaustive search instead of a directed search (see qh_findbestnew in geom2.c).

»How Qhull adds a point

»rbox 100 s P0.5,0.5,0.5 | qconvex Ga QG0 >eg.10a.sphere.visible

The next 4 examples show how Qhull adds a point. The point [0.5,0.5,0.5] is at one corner of the bounding box. Qhull adds a point using the beneath-beyond algorithm. First Qhull finds all of the facets that are visible from the point. Qhull will replace these facets with new facets.

»rbox 100 s P0.5,0.5,0.5|qconvex Ga QG-0 >eg.10b.sphere.beyond

These are the facets that are not visible from the point. Qhull will keep these facets.

»rbox 100 s P0.5,0.5,0.5 | qconvex PG Ga QG0 >eg.10c.sphere.horizon

These facets are the horizon facets; they border the visible facets. The inside edges are the horizon ridges. Each horizon ridge will form the base for a new facet.

»rbox 100 s P0.5,0.5,0.5 | qconvex Ga QV0 PgG >eg.10d.sphere.cone

This is the cone of points from the new point to the horizon facets. Try combining this image with eg.10c.sphere.horizon and eg.10a.sphere.visible.

»rbox 100 s P0.5,0.5,0.5 | qconvex Ga >eg.10e.sphere.new

This is the convex hull after [0.5,0.5,0.5] has been added. Note that in actual practice, the above sequence would never happen. Unlike the randomized algorithms, Qhull always processes a point that is furthest in an outside set. A point like [0.5,0.5,0.5] would be one of the first points processed.

»rbox 100 s P0.5,0.5,0.5 | qhull Ga QV0g Q0 >eg.14.sphere.corner

The 'QVn', 'QGn ' and 'Pdk' options define good facets for Qhull. In this case 'QV0' defines the 0'th point [0.5,0.5,0.5] as the good vertex, and 'Qg' tells Qhull to only build facets that might be part of a good facet. This technique reduces output size in low dimensions. It does not work with facet merging.

»Triangulated output or joggled input

»rbox 500 W0 | qconvex QR0 Qc Gvp >eg.15a.surface

This is the convex hull of 500 points on the surface of a cube. Note the large, non-simplicial facet for each face. Qhull merges non-convex facets.

If the facets were not merged, Qhull would report precision problems. For example, turn off facet merging with option 'Q0'. Qhull may report concave facets, flipped facets, or other precision errors:

rbox 500 W0 | qhull QR0 Q0

»rbox 500 W0 | qconvex QR0 Qt Qc Gvp >eg.15b.triangle

Like the previous examples, this is the convex hull of 500 points on the surface of a cube. Option 'Qt' triangulates the non-simplicial facets. Triangulated output is particularly helpful for Delaunay triangulations.

»rbox 500 W0 | qconvex QR0 QJ5e-2 Qc Gvp >eg.15c.joggle

This is the convex hull of 500 joggled points on the surface of a cube. The option 'QJ5e-2' sets a very large joggle to make the effect visible. Notice that all of the facets are triangles. If you rotate the cube, you'll see red-yellow lines for coplanar points.

With option 'QJ', Qhull joggles the input to avoid precision problems. It adds a small random number to each input coordinate. If a precision error occurs, it increases the joggle and tries again. It repeats this process until no precision problems occur.

Joggled input is a simple solution to precision problems in computational geometry. Qhull can also merge facets to handle precision problems. See Merged facets or joggled input.

»Delaunay and Voronoi diagrams

»qdelaunay Qt <eg.data.17 GnraD2 >eg.17a.delaunay.2

The input file, eg.data.17, consists of a square, 15 random points within the outside half of the square, and 6 co-circular points centered on the square.

The Delaunay triangulation is the triangulation with empty circumcircles. The input for this example is unusual because it includes six co-circular points. Every triangular subset of these points has the same circumcircle. Option 'Qt' triangulates the co-circular facet.

»qdelaunay <eg.data.17 GnraD2 >eg.17b.delaunay.2i

This is the same example without triangulated output ('Qt'). qdelaunay merges the non-unique Delaunay triangles into a hexagon.

»qdelaunay <eg.data.17 Ga >eg.17c.delaunay.2-3

This is how Qhull generated both diagrams. Use Geomview's 'obscure' menu to turn off normalization, and Geomview's 'cameras' menu to turn off perspective. Then load this object with one of the previous diagrams.

The points are lifted to a paraboloid by summing the squares of each coordinate. These are the light blue points. Then the convex hull is taken. That's what you see here. If you look up the Z-axis, you'll see that points and edges coincide.

»qvoronoi QJ <eg.data.17 Gna >eg.17d.voronoi.2

The Voronoi diagram is the dual of the Delaunay triangulation. Here you see the original sites and the Voronoi vertices. Notice the each vertex is equidistant from three sites. The edges indicate the Voronoi region for a site. Qhull does not draw the unbounded edges. Instead, it draws extra edges to close the unbounded Voronoi regions. You may find it helpful to enclose the input points in a square. You can compute the unbounded rays from option 'Fo'.

Instead of triangulated output ('Qt'), this example uses joggled input ('QJ'). Normally, you should use neither 'QJ' nor 'Qt' for Voronoi diagrams.

»qvoronoi <eg.data.17 Gna >eg.17e.voronoi.2i

This looks the same as the previous diagrams, but take a look at the data. Run 'qvoronoi p <eg/eg.data.17'. This prints the Voronoi vertices.

With 'QJ', there are four nearly identical Voronoi vertices within 10^-11 of the origin. Option 'QJ' joggled the input. After the joggle, the cocircular input sites are no longer cocircular. The corresponding Voronoi vertices are similar but not identical.

This example does not use options 'Qt' or 'QJ'. The cocircular input sites define one Voronoi vertex near the origin.

Option 'Qt' would triangulate the corresponding Delaunay region into four triangles. Each triangle is assigned the same Voronoi vertex.

» rbox c G0.1 d | qdelaunay Gt Qz <eg.17f.delaunay.3

This is the 3-d Delaunay triangulation of a small cube inside a prism. Since the outside ridges are transparent, it shows the interior of the outermost facets. If you slice open the triangulation with Geomview's ginsu, you will see that the innermost facet is a cube. Note the use of 'Qz' to add a point "at infinity". This avoids a degenerate input due to cospherical points.

»rbox 10 D2 d | qdelaunay Qu G >eg.18a.furthest.2-3

The furthest-site Voronoi diagram contains Voronoi regions for points that are furthest from an input site. It is the dual of the furthest-site Delaunay triangulation. You can determine the furthest-site Delaunay triangulation from the convex hull of the lifted points (eg.17c.delaunay.2-3). The upper convex hull (blue) generates the furthest-site Delaunay triangulation.

»rbox 10 D2 d | qdelaunay Qu Pd2 G >eg.18b.furthest-up.2-3

This is the upper convex hull of the preceding example. The furthest-site Delaunay triangulation is the projection of the upper convex hull back to the input points. The furthest-site Voronoi vertices are the circumcenters of the furthest-site Delaunay triangles.

»rbox 10 D2 d | qvoronoi Qu Gv >eg.18c.furthest.2

This shows an incomplete furthest-site Voronoi diagram. It only shows regions with more than two vertices. The regions are artificially truncated. The actual regions are unbounded. You can print the regions' vertices with 'qvoronoi Qu o'.

Use Geomview's 'obscure' menu to turn off normalization, and Geomview's 'cameras' menu to turn off perspective. Then load this with the upper convex hull.

»rbox 10 D3 | qvoronoi QV5 p | qconvex G >eg.19.voronoi.region.3

This shows the Voronoi region for input site 5 of a 3-d Voronoi diagram.

»Facet merging for imprecision

»rbox r s 20 Z1 G0.2 | qconvex G >eg.20.cone

There are two things unusual about this cone. One is the large flat disk at one end and the other is the rectangles about the middle. That's how the points were generated, and if those points were exact, this is the correct hull. But rbox used floating point arithmetic to generate the data. So the precise convex hull should have been triangles instead of rectangles. By requiring convexity, Qhull has recovered the original design.

»rbox 200 s | qhull Q0 R0.01 Gav Po >eg.21a.roundoff.errors

This is the convex hull of 200 cospherical points with precision errors ignored ('Q0'). To demonstrate the effect of roundoff error, we've added a random perturbation ('R0.01') to every distance and hyperplane calculation. Qhull, like all other convex hull algorithms with floating point arithmetic, makes inconsistent decisions and generates wildly wrong results. In this case, one or more facets are flipped over. These facets have the wrong color. You can also turn on 'normals' in Geomview's appearances menu and turn off 'facing normals'. There should be some white lines pointing in the wrong direction. These correspond to flipped facets.

Different machines may not produce this picture. If your machine generated a long error message, decrease the number of points or the random perturbation ('R0.01'). If it did not report flipped facets, increase the number of points or perturbation.

»rbox 200 s | qconvex Qc R0.01 Gpav >eg.21b.roundoff.fixed

Qhull handles the random perturbations and returns an imprecise sphere. In this case, the output is a weak approximation to the points. This is because a random perturbation of 'R0.01 ' is equivalent to losing all but 1.8 digits of precision. The outer planes float above the points because Qhull needs to allow for the maximum roundoff error.

If you start with a smaller random perturbation, you can use joggle ('QJn') to avoid precision problems. You need to set n significantly larger than the random perturbation. For example, try 'rbox 200 s | qconvex Qc R1e-4 QJ1e-1'.

»rbox 1000 s| qconvex C0.01 Qc Gcrp >eg.22a.merge.sphere.01

»rbox 1000 s| qconvex C-0.01 Qc Gcrp >eg.22b.merge.sphere.-01

»rbox 1000 s| qconvex C0.05 Qc Gcrpv >eg.22c.merge.sphere.05

»rbox 1000 s| qconvex C-0.05 Qc Gcrpv >eg.22d.merge.sphere.-05

The next four examples compare post-merging and pre-merging ('Cn' vs. 'C-n'). Qhull uses '-' as a flag to indicate pre-merging.

Post-merging happens after the convex hull is built. During post-merging, Qhull repeatedly merges an independent set of non-convex facets. For a given set of parameters, the result is about as good as one can hope for.

Pre-merging does the same thing as post-merging, except that it happens after adding each point to the convex hull. With pre-merging, Qhull guarantees a convex hull, but the facets are wider than those from post-merging. If a pre-merge option is not specified, Qhull handles machine round-off errors.

You may see coplanar points appearing slightly outside the facets of the last example. This is becomes Geomview moves line segments forward toward the viewer. You can avoid the effect by setting 'lines closer' to '0' in Geomview's camera menu.

»rbox 1000 | qconvex s Gcprvah C0.1 Qc >eg.23.merge.cube

Here's the 3-d imprecise cube with all of the Geomview options. There's spheres for the vertices, radii for the coplanar points, dots for the interior points, hyperplane intersections, centrums, and inner and outer planes. The radii are shorter than the spheres because this uses post-merging ('C0.1') instead of pre-merging.

»4-d objects

With Qhull and Geomview you can develop an intuitive sense of 4-d surfaces. When you get into trouble, think of viewing the surface of a 3-d sphere in a 2-d plane.

»rbox 5000 D4 | qconvex s GD0v Pd0:0.5 C-0.02 C0.1 >eg.24.merge.cube.4d-in-3d

Here's one facet of the imprecise cube in 4-d. It's projected into 3-d (the 'GDn' option drops dimension n). Each ridge consists of two triangles between this facet and the neighboring facet. In this case, Geomview displays the topological ridges, i.e., as triangles between three vertices. That is why the cube looks lopsided.

»rbox 5000 D4 | qconvex s C-0.02 C0.1 Gh >eg.30.4d.merge.cube

Here is the equivalent in 4-d of the imprecise square and imprecise cube. It's the imprecise convex hull of 5000 random points in a hypercube. It's a full 4-d object so Geomview's ginsu does not work. If you view it in Geomview, you'll be inside the hypercube. To view 4-d objects directly, either load the 4dview module or the ndview module. For 4dview, you must have started Geomview in the same directory as the object. For ndview, initialize a set of windows with the prefab menu, and load the object through Geomview. The 4dview module includes an option for slicing along any hyperplane. If you do this in the x, y, or z plane, you'll see the inside of a hypercube.

The 'Gh' option prints the geometric intersections between adjacent facets. Note the strong convexity constraint for post-merging ('C0.1'). It deletes the small facets.

»rbox 20 D3 | qdelaunay G >eg.31.4d.delaunay

The Delaunay triangulation of 3-d sites corresponds to a 4-d convex hull. You can't see 4-d directly but each facet is a 3-d object that you can project to 3-d. This is exactly the same as projecting a 2-d facet of a soccer ball onto a plane.

Here we see all of the facets together. You can use Geomview's ndview to look at the object from several directions. Try turning on edges in the appearance menu. You'll notice that some edges seem to disappear. That's because the object is actually two sets of overlapping facets.

You can slice the object apart using Geomview's 4dview. With 4dview, try slicing along the w axis to get a single set of facets and then slice along the x axis to look inside. Another interesting picture is to slice away the equator in the w dimension.

»rbox 30 s D4 | qconvex s G Pd0d1d2D3

This is the positive octant of the convex hull of 30 4-d points. When looking at 4-d, it's easier to look at just a few facets at once. If you picked a facet that was directly above you, then that facet looks exactly the same in 3-d as it looks in 4-d. If you pick several facets, then you need to imagine that the space of a facet is rotated relative to its neighbors. Try Geomview's ndview on this example.

»Halfspace intersections

»rbox 10 r s Z1 G0.3 | qconvex G >eg.33a.cone

»rbox 10 r s Z1 G0.3 | qconvex FV n | qhalf G >eg.33b.cone.dual

»rbox 10 r s Z1 G0.3 | qconvex FV n | qhalf Fp | qconvex G >eg.33c.cone.halfspace

These examples illustrate halfspace intersection. The first picture is the convex hull of two 20-gons plus an apex. The second picture is the dual of the first. Try loading both at once. Each vertex of the second picture corresponds to a facet or halfspace of the first. The vertices with four edges correspond to a facet with four neighbors. Similarly the facets correspond to vertices. A facet's normal coefficients divided by its negative offset is the vertice's coordinates. The coordinates are the intersection of the original halfspaces.

The third picture shows how Qhull can go back and forth between equivalent representations. It starts with a cone, generates the halfspaces that define each facet of the cone, and then intersects these halfspaces. Except for roundoff error, the third picture is a duplicate of the first.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull examples: Table of Contents (please wait while loading)


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-faq.htm b/html/qh-faq.htm index 9f34318..baf5dcf 100644 --- a/html/qh-faq.htm +++ b/html/qh-faq.htm @@ -1,1538 +1,1538 @@ Qhull FAQ

Up: Home page for Qhull (http://www.qhull.org)
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: FAQ: Table of Contents (please wait while loading)


[4-d cube] Frequently Asked Questions about Qhull

If your question does not appear here, see:

Qhull is a general dimension code for computing convex hulls, Delaunay triangulations, halfspace intersections about a point, Voronoi diagrams, furthest-site Delaunay triangulations, and furthest-site Voronoi diagrams. These structures have applications in science, engineering, statistics, and mathematics. For a detailed introduction, see O'Rourke ['94], Computational Geometry in C.

There are separate programs for each application of Qhull. These programs disable experimental and inappropriate options. If you prefer, you may use Qhull directly. All programs run the same code.

Version 3.1 added triangulated output ('Qt'). It should be used for Delaunay triangulations instead of using joggled input ('QJ').

Brad Barber, Arlington MA, 2010/01/09

-

Copyright © 1998-2012 C.B. Barber

+

Copyright © 1998-2015 C.B. Barber


»FAQ: Table of Contents

Within each category, the most recently asked questions are first.

  • Startup questions
    • How do I run Qhull from Windows?
    • How do I enter points for Qhull?
    • How do I learn to use Qhull?
  • Convex hull questions
    • How do I report just the area and volume of a convex hull?
    • Why are there extra points in a 4-d or higher convex hull?
    • How do I report duplicate vertices?
  • Delaunay triangulation questions
    • How do I get rid of nearly flat Delaunay triangles?
    • How do I find the Delaunay triangle or Voronoi region that is closest to a point?
    • How do I compute the Delaunay triangulation of a non-convex object?
    • How do I mesh a volume from a set of triangulated surface points?
    • Can Qhull produce a triangular mesh for an object?
    • For 3-d Delaunay triangulations, how do I report the triangles of each tetrahedron?
    • How do I construct a 3-d Delaunay triangulation?
    • How do I get the triangles for a 2-d Delaunay triangulation and the vertices of its Voronoi diagram?
    • Can Qhull triangulate a hundred 16-d points?
  • Voronoi diagram questions
    • See also "Delaunay diagram questions". Qhull computes the Voronoi diagram from the Delaunay triagulation.
    • How do I compute the volume of a Voronoi region?
    • How do I get the radii of the empty spheres for each Voronoi vertex?
    • What is the Voronoi diagram of a square?
    • How do I construct the Voronoi diagram of cospherical points?
    • Can Qhull compute the unbounded rays of the Voronoi diagram?
  • Approximation questions
    • How do I approximate data with a simplex?
  • Halfspace questions
    • How do I compute the intersection of halfspaces with Qhull?
  • Qhull library questions
    • Is Qhull available for Mathematica, Matlab, or Maple?
    • Why are there too few ridges?
    • Can Qhull use coordinates without placing them in a data file?
    • How large are Qhull's data structures?
    • Can Qhull construct convex hulls and Delaunay triangulations one point at a time?
    • How do I visit the ridges of a Delaunay triangulation?
    • How do I visit the Delaunay facets?
    • When is a point outside or inside a facet?
    • How do I find the facet that is closest to a point?
    • How do I find the Delaunay triangle or Voronoi region that is closest to a point?
    • How do I list the vertices?
    • How do I test code that uses the Qhull library?
    • When I compute a plane equation from a facet, I sometimes get an outward-pointing normal and sometimes an inward-pointing normal

»Startup questions

»How do I run Qhull from Windows?

Qhull is a console program. You will first need a command window (i.e., a "command prompt"). You can double click on 'eg\Qhull-go.bat'.

  • Type 'qconvex', 'qdelaunay', 'qhalf', 'qvoronoi, 'qhull', and 'rbox' for a synopsis of each program.
  • Type 'rbox c D2 | qconvex s i' to compute the convex hull of a square.
  • Type 'rbox c D2 | qconvex s i TO results.txt' to write the results to the file 'results.txt'. A summary is still printed on the the console.
  • Type 'rbox c D2' to see the input format for qconvex.
  • Type 'qconvex < data.txt s i TO results.txt' to read input data from 'data.txt'.
  • If you want to enter data by hand, type 'qconvex s i TO results.txt' to read input data from the console. Type in the numbers and end with a ctrl-D.

»How do I enter points for Qhull?

Qhull takes its data from standard input. For example, create a file named 'data.txt' with the following contents:

 2  #sample 2-d input
 5  #number of points
 1 2  #coordinates of points
 -1.1 3
 3 2.2
 4 5
 -10 -10
 

Then call qconvex with 'qconvex < data.txt'. It will print a summary of the convex hull. Use 'qconvex < data.txt o' to print the vertices and edges. See also input format.

You can generate sample data with rbox, e.g., 'rbox 10' generates 10 random points in 3-d. Use a pipe ('|') to run rbox and qhull together, e.g.,

rbox c | qconvex o

computes the convex hull of a cube.

»How do I learn to use Qhull?

First read:

Look at Qhull's on-line documentation:

  • 'qconvex' gives a synopsis of qconvex and its options
  • 'rbox' lists all of the options for generating point sets
  • 'qconvex - | more' lists the options for qconvex
  • 'qconvex .' gives a concise list of options
  • 'qdelaunay', 'qhalf', 'qvoronoi', and 'qhull' also have a synopsis and option list

Then try out the Qhull programs on small examples.

  • 'rbox c' lists the vertices of a cube
  • 'rbox c | qconvex' is the convex hull of a cube
  • 'rbox c | qconvex o' lists the vertices and facets of a cube
  • 'rbox c | qconvex Qt o' triangulates the cube
  • 'rbox c | qconvex QJ o' joggles the input and triangulates the cube
  • 'rbox c D2 | qconvex' generates the convex hull of a square
  • 'rbox c D4 | qconvex' generates the convex hull of a hypercube
  • 'rbox 6 s D2 | qconvex p Fx' lists 6 random points in a circle and lists the vertices of their convex hull in order
  • 'rbox c D2 c G2 | qdelaunay' computes the Delaunay triangulation of two embedded squares. It merges the cospherical facets.
  • 'rbox c D2 c G2 | qdelaunay Qt' computes the Delaunay triangulation of two embedded squares. It triangulates the cospherical facets.
  • 'rbox c D2 c G2 | qvoronoi o' computes the corresponding Voronoi vertices and regions.
  • 'rbox c D2 c G2 | qvoronio Fv' shows the Voronoi diagram for the previous example. Each line is one edge of the diagram. The first number is 4, the next two numbers list a pair of input sites, and the last two numbers list the corresponding pair of Voronoi vertices.

Install Geomview if you are running SGI Irix, Solaris, SunOS, Linux, HP, IBM RS/6000, DEC Alpha, or Next. You can then visualize the output of Qhull. Qhull comes with Geomview examples.

Then try Qhull with a small example of your application. Work out the results by hand. Then experiment with Qhull's options to find the ones that you need.

You will need to decide how Qhull should handle precision problems. It can triangulate the output ('Qt'), joggle the input ('QJ'), or merge facets (the default).

  • With joggle, Qhull produces simplicial (i.e., triangular) output by joggling the input. After joggle, no points are cocircular or cospherical.
  • With facet merging, Qhull produces a better approximation and does not modify the input.
  • With triangulated output, Qhull merges facets and triangulates the result.
  • See Merged facets or joggled input.

»Convex hull questions

»How do I report just the area and volume of a convex hull?

Use option 'FS'. For example,
 C:\qhull>rbox 10 | qconvex FS
 0
 2 2.192915621644613 0.2027867899638665
 
 C:\qhull>rbox 10 | qconvex FA
 
 Convex hull of 10 points in 3-d:
 
   Number of vertices: 10
   Number of facets: 16
 
 Statistics for: RBOX 10 | QCONVEX FA
 
   Number of points processed: 10
   Number of hyperplanes created: 28
   Number of distance tests for qhull: 44
   CPU seconds to compute hull (after input):  0
   Total facet area:   2.1929156
   Total volume:       0.20278679
 

»Why are there extra points in a 4-d or higher convex hull?

You may see extra points if you use options 'i' or 'Ft' without using triangulated output ('Qt'). The extra points occur when a facet is non-simplicial (i.e., a facet with more than d vertices). For example, Qhull reports the following for one facet of the convex hull of a hypercube. Option 'Pd0:0.5' returns the facet along the positive-x axis:

 rbox c D4 | qconvex i Pd0:0.5
 12
 17 13 14 15
 17 13 12 14
 17 11 13 15
 17 14 11 15
 17 10 11 14
 17 14 12 8
 17 12 13 8
 17 10 14 8
 17 11 10 8
 17 13 9 8
 17 9 11 8
 17 11 9 13
 

The 4-d hypercube has 16 vertices; so point "17" was added by qconvex. Qhull adds the point in order to report a simplicial decomposition of the facet. The point corresponds to the "centrum" which Qhull computes to test for convexity.

Triangulate the output ('Qt') to avoid the extra points. Since the hypercube is 4-d, each simplicial facet is a tetrahedron.

 C:\qhull3.1>rbox c D4 | qconvex i Pd0:0.5 Qt
 9
 9 13 14 15
 12 9 13 14
 9 11 13 15
 11 9 14 15
 9 10 11 14
 12 9 14 8
 9 12 13 8
 9 10 14 8
 10 9 11 8
 

Use the 'Fv' option to print the vertices of simplicial and non-simplicial facets. For example, here is the same hypercube facet with option 'Fv' instead of 'i':

 C:\qhull>rbox c D4 | qconvex Pd0:0.5 Fv
 1
 8 9 10 12 11 13 14 15 8
 

The coordinates of the extra point are printed with the 'Ft' option.

 rbox c D4 | qconvex Pd0:0.5 Ft
 4
 17 12 3
   -0.5   -0.5   -0.5   -0.5
   -0.5   -0.5   -0.5    0.5
   -0.5   -0.5    0.5   -0.5
   -0.5   -0.5    0.5    0.5
   -0.5    0.5   -0.5   -0.5
   -0.5    0.5   -0.5    0.5
   -0.5    0.5    0.5   -0.5
   -0.5    0.5    0.5    0.5
    0.5   -0.5   -0.5   -0.5
    0.5   -0.5   -0.5    0.5
    0.5   -0.5    0.5   -0.5
    0.5   -0.5    0.5    0.5
    0.5    0.5   -0.5   -0.5
    0.5    0.5   -0.5    0.5
    0.5    0.5    0.5   -0.5
    0.5    0.5    0.5    0.5
    0.5      0      0      0
 4 16 13 14 15
 4 16 13 12 14
 4 16 11 13 15
 4 16 14 11 15
 4 16 10 11 14
 4 16 14 12 8
 4 16 12 13 8
 4 16 10 14 8
 4 16 11 10 8
 4 16 13 9 8
 4 16 9 11 8
 4 16 11 9 13
 

»How do I report duplicate vertices?

There's no direct way. You can use option 'FP' to report the distance to the nearest vertex for coplanar input points. Select the minimum distance for a duplicated vertex, and locate all input sites less than this distance.

For Delaunay triangulations, all coplanar points are nearly incident to a vertex. If you want a report of coincident input sites, do not use option 'QJ'. By adding a small random quantity to each input coordinate, it prevents coincident input sites.

»Delaunay triangulation questions

»How do I get rid of nearly flat Delaunay triangles?

Nearly flat triangles occur when boundary points are nearly collinear or coplanar. They also occur for nearly coincident points. Both events can easily occur when using joggle. For example (rbox 10 W0 D2 | qdelaunay QJ Fa) lists the areas of the Delaunay triangles of 10 points on the boundary of a square. Some of these triangles are nearly flat. This occurs when one point is joggled inside of two other points. In this case, nearly flat triangles do not occur with triangulated output (rbox 10 W0 D2 | qdelaunay Qt Fa).

Another example, (rbox c P0 P0 D2 | qdelaunay QJ Fa), computes the areas of the Delaunay triangles for the unit square and two instances of the origin. Four of the triangles have an area of 0.25 while two have an area of 2.0e-11. The later are due to the duplicated origin. With triangulated output (rbox c P0 P0 D2 | qdelaunay Qt Fa) there are four triangles of equal area.

Nearly flat triangles also occur without using joggle. For example, (rbox c P0 P0,0.4999999999 | qdelaunay Fa), computes the areas of the Delaunay triangles for the unit square, a nearly collinear point, and the origin. One triangle has an area of 3.3e-11.

Unfortunately, none of Qhull's merging options remove nearly flat Delaunay triangles due to nearly collinear or coplanar boundary points. The merging options concern the empty circumsphere property of Delaunay triangles. This is independent of the area of the Delaunay triangles. Qhull does handle nearly coincident points.

You can handle collinear or coplanar boundary points by enclosing the points in a box. For example, (rbox c P0 P0,0.4999999999 c G1 | qdelaunay Fa), surrounds the previous points with [(1,1), (1,-1), (-1,-1), (-1, 1)]. Its Delaunay triangulation does not include a nearly flat triangle. The box also simplifies the graphical output from Qhull.

Without joggle, Qhull lists coincident points as "coplanar" points. For example, (rbox c P0 P0 D2 | qdelaunay Fa), ignores the duplicated origin and lists four triangles of size 0.25. Use 'Fc' to list the coincident points (e.g., rbox c P0 P0 D2 | qdelaunay Fc).

There is no easy way to determine coincident points with joggle. Joggle removes all coincident, cocircular, and cospherical points before running Qhull. Instead use facet merging (the default) or triangulated output ('Qt').

»How do I compute the Delaunay triangulation of a non-convex object?

A similar question is "How do I mesh a volume from a set of triangulated surface points?"

This is an instance of the constrained Delaunay Triangulation problem. Qhull does not handle constraints. The boundary of the Delaunay triangulation is always convex. But if the input set contains enough points, the triangulation will include the boundary. The number of points needed depends on the input.

Shewchuk has developed a theory of constrained Delaunay triangulations. See his paper at the 1998 Computational Geometry Conference. Using these ideas, constraints could be added to Qhull. They would have many applications.

There is a large literature on mesh generation and many commercial offerings. For pointers see Owen's Meshing Research Corner and Schneiders' Finite Element Mesh Generation page.

»Can Qhull produce a triangular mesh for an object?

Yes for convex objects, no for non-convex objects. For non-convex objects, it triangulates the concavities. Unless the object has many points on its surface, triangles may cross the surface.

»For 3-d Delaunay triangulations, how do I report the triangles of each tetrahedron?

For points in general position, a 3-d Delaunay triangulation generates tetrahedron. Each face of a tetrahedron is a triangle. For example, the 3-d Delaunay triangulation of random points on the surface of a cube, is a cellular structure of tetrahedron.

Use triangulated output ('qdelaunay Qt i') or joggled input ('qdelaunay QJ i') to generate the Delaunay triangulation. Option 'i' reports each tetrahedron. The triangles are every combination of 3 vertices. Each triangle is a "ridge" of the Delaunay triangulation.

For example,

         rbox 10 | qdelaunay Qt i
         14
         9 5 8 7
         0 9 8 7
         5 3 8 7
         3 0 8 7
         5 4 8 1
         4 6 8 1
         2 9 5 8
         4 2 5 8
         4 2 9 5
         6 2 4 8
         9 2 0 8
         2 6 0 8
         2 4 9 1
         2 6 4 1
 

is the Delaunay triangulation of 10 random points. Ridge 9-5-8 occurs twice. Once for tetrahedron 9 5 8 7 and the other for tetrahedron 2 9 5 8.

You can also use the Qhull library to generate the triangles. See "How do I visit the ridges of a Delaunay triangulation?"

»How do I construct a 3-d Delaunay triangulation?

For 3-d Delaunay triangulations with cospherical input sites, use triangulated output ('Qt') or joggled input ('QJ'). Otherwise option 'i' will triangulate non-simplicial facets by adding a point to the facet.

If you want non-simplicial output for cospherical sites, use option 'Fv' or 'o'. For option 'o', ignore the last coordinate. It is the lifted coordinate for the corresponding convex hull in 4-d.

The following example is a cube inside a tetrahedron. The 8-vertex facet is the cube. Ignore the last coordinates.

 C:\qhull>rbox r y c G0.1 | qdelaunay Fv
 4
 12 20 44
    0.5      0      0 0.3055555555555555
    0    0.5      0 0.3055555555555555
    0      0    0.5 0.3055555555555555
   -0.5   -0.5   -0.5 0.9999999999999999
   -0.1   -0.1   -0.1 -6.938893903907228e-018
   -0.1   -0.1    0.1 -6.938893903907228e-018
   -0.1    0.1   -0.1 -6.938893903907228e-018
   -0.1    0.1    0.1 -6.938893903907228e-018
    0.1   -0.1   -0.1 -6.938893903907228e-018
    0.1   -0.1    0.1 -6.938893903907228e-018
    0.1    0.1   -0.1 -6.938893903907228e-018
    0.1    0.1    0.1 -6.938893903907228e-018
 4 2 11 1 0
 4 10 1 0 3
 4 11 10 1 0
 4 2 9 0 3
 4 9 11 2 0
 4 7 2 1 3
 4 11 7 2 1
 4 8 10 0 3
 4 9 8 0 3
 5 8 9 10 11 0
 4 10 6 1 3
 4 6 7 1 3
 5 6 8 10 4 3
 5 6 7 10 11 1
 4 5 9 2 3
 4 7 5 2 3
 5 5 8 9 4 3
 5 5 6 7 4 3
 8 5 6 8 7 9 10 11 4
 5 5 7 9 11 2
 

If you want simplicial output use options 'Qt i' or 'QJ i', e.g.,

 rbox r y c G0.1 | qdelaunay Qt i
 31
 2 11 1 0
 11 10 1 0
 9 11 2 0
 11 7 2 1
 8 10 0 3
 9 8 0 3
 10 6 1 3
 6 7 1 3
 5 9 2 3
 7 5 2 3
 9 8 10 11
 8 10 11 0
 9 8 11 0
 6 8 10 4
 8 6 10 3
 6 8 4 3
 6 7 10 11
 10 6 11 1
 6 7 11 1
 8 5 4 3
 5 8 9 3
 5 6 4 3
 6 5 7 3
 5 9 10 11
 8 5 9 10
 7 5 10 11
 5 6 7 10
 8 5 10 4
 5 6 10 4
 5 9 11 2
 7 5 11 2
 

»How do I get the triangles for a 2-d Delaunay triangulation and the vertices of its Voronoi diagram?

To compute the Delaunay triangles indexed by the indices of the input sites, use

rbox 10 D2 | qdelaunay Qt i

To compute the Voronoi vertices and the Voronoi region for each input site, use

rbox 10 D2 | qvoronoi o

To compute each edge ("ridge") of the Voronoi diagram for each pair of adjacent input sites, use

rbox 10 D2 | qvoronoi Fv

To compute the area and volume of the Voronoi region for input site 5 (site 0 is the first one), use

rbox 10 D2 | qvoronoi QV5 p | qconvex s FS

To compute the lines ("hyperplanes") that define the Voronoi region for input site 5, use

rbox 10 D2 | qvoronoi QV5 p | qconvex n

or

rbox 10 D2 | qvoronoi QV5 Fi Fo

To list the extreme points of the input sites use

rbox 10 D2 | qdelaunay Fx

You will get the same point ids with

rbox 10 D2 | qconvex Fx

»Can Qhull triangulate a hundred 16-d points?

No. This is an immense structure. A triangulation of 19, 16-d points has 43 simplices. If you add one point at a time, the triangulation increased as follows: 43, 189, 523, 1289, 2830, 6071, 11410, 20487. The last triangulation for 26 points used 13 megabytes of memory. When Qhull uses virtual memory, it becomes too slow to use.

»Voronoi diagram questions

»How do I compute the volume of a Voronoi region?

For each Voronoi region, compute the convex hull of the region's Voronoi vertices. The volume of each convex hull is the volume of the corresponding Vornoi region.

For example, to compute the volume of the bounded Voronoi region about [0,0,0]: output the origin's Voronoi vertices and compute the volume of their convex hull. The last number from option 'FS' is the volume.

 rbox P0 10 | qvoronoi QV0 p | qhull FS
 0
 2 1.448134756744281 0.1067973560800857
 

For another example, see How do I get the triangles for a 2-d Delaunay triangulation and the vertices of its Voronoi diagram?

This approach is slow if you are using the command line. A faster approcach is to call Qhull from a program. The fastest method is Clarkson's hull program. It computes the volume for all Voronoi regions.

An unbounded Voronoi region does not have a volume.

»How do I get the radii of the empty spheres for each Voronoi vertex?

Use option 'Fi' to list each bisector (i.e. Delaunay ridge). Then compute the minimum distance for each Voronoi vertex.

There's other ways to get the same information. Let me know if you find a better method.

»What is the Voronoi diagram of a square?

Consider a square,

 C:\qhull>rbox c D2
 2 RBOX c D2
 4
   -0.5   -0.5
   -0.5    0.5
    0.5   -0.5
    0.5    0.5
 

There's two ways to compute the Voronoi diagram: with facet merging or with joggle. With facet merging, the result is:

 C:\qhull>rbox c D2 | qvoronoi Qz
 
 Voronoi diagram by the convex hull of 5 points in 3-d:
 
   Number of Voronoi regions and at-infinity: 5
   Number of Voronoi vertices: 1
   Number of facets in hull: 5
 
 Statistics for: RBOX c D2 | QVORONOI Qz
 
   Number of points processed: 5
   Number of hyperplanes created: 7
   Number of distance tests for qhull: 8
   Number of merged facets: 1
   Number of distance tests for merging: 29
   CPU seconds to compute hull (after input):  0
 
 C:\qhull>rbox c D2 | qvoronoi Qz o
 2
 2 5 1
 -10.101 -10.101
      0      0
 2 0 1
 2 0 1
 2 0 1
 2 0 1
 0
 
 C:\qhull>rbox c D2 | qvoronoi Qz Fv
 4
 4 0 1 0 1
 4 0 2 0 1
 4 1 3 0 1
 4 2 3 0 1
 

There is one Voronoi vertex at the origin and rays from the origin along each of the coordinate axes. The last line '4 2 3 0 1' means that there is a ray that bisects input points #2 and #3 from infinity (vertex 0) to the origin (vertex 1). Option 'Qz' adds an artificial point since the input is cocircular. Coordinates -10.101 indicate the vertex at infinity.

With triangulated output, the Voronoi vertex is duplicated:

 C:\qhull3.1>rbox c D2 | qvoronoi Qt Qz
 
 Voronoi diagram by the convex hull of 5 points in 3-d:
 
   Number of Voronoi regions and at-infinity: 5
   Number of Voronoi vertices: 2
   Number of triangulated facets: 1
 
 Statistics for: RBOX c D2 | QVORONOI Qt Qz
 
   Number of points processed: 5
   Number of hyperplanes created: 7
   Number of facets in hull: 6
   Number of distance tests for qhull: 8
   Number of distance tests for merging: 33
   Number of distance tests for checking: 30
   Number of merged facets: 1
   CPU seconds to compute hull (after input): 0.05
 
 C:\qhull3.1>rbox c D2 | qvoronoi Qt Qz o
 2
 3 5 1
 -10.101 -10.101
      0      0
      0      0
 3 2 0 1
 2 1 0
 2 2 0
 3 2 0 1
 0
 
 C:\qhull3.1>rbox c D2 | qvoronoi Qt Qz Fv
 4
 4 0 2 0 2
 4 0 1 0 1
 4 1 3 0 1
 4 2 3 0 2
 

With joggle, the input is no longer cocircular and the Voronoi vertex is split into two:

 C:\qhull>rbox c D2 | qvoronoi Qt Qz
 
 C:\qhull>rbox c D2 | qvoronoi QJ o
 2
 3 4 1
 -10.101 -10.101
 -4.71511718558304e-012 -1.775812830118184e-011
 9.020340030474472e-012 -4.02267108512433e-012
 2 0 1
 3 2 1 0
 3 2 0 1
 2 2 0
 
 C:\qhull>rbox c D2 | qvoronoi QJ Fv
 5
 4 0 2 0 1
 4 0 1 0 1
 4 1 2 1 2
 4 1 3 0 2
 4 2 3 0 2
 

Note that the Voronoi diagram includes the same rays as before plus a short edge between the two vertices.

»How do I construct the Voronoi diagram of cospherical points?

Three-d terrain data can be approximated with cospherical points. The Delaunay triangulation of cospherical points is the same as their convex hull. If the points lie on the unit sphere, the facet normals are the Voronoi vertices [via S. Fortune].

For example, consider the points {[1,0,0], [-1,0,0], [0,1,0], ...}. Their convex hull is:

 rbox d G1 | qconvex o
 3
 6 8 12
      0      0     -1
      0      0      1
      0     -1      0
      0      1      0
     -1      0      0
      1      0      0
 3 3 1 4
 3 1 3 5
 3 0 3 4
 3 3 0 5
 3 2 1 5
 3 1 2 4
 3 2 0 4
 3 0 2 5
 

The facet normals are:

 rbox d G1 | qconvex n
 4
 8
 -0.5773502691896258  0.5773502691896258  0.5773502691896258 -0.5773502691896258
  0.5773502691896258  0.5773502691896258  0.5773502691896258 -0.5773502691896258
 -0.5773502691896258  0.5773502691896258 -0.5773502691896258 -0.5773502691896258
  0.5773502691896258  0.5773502691896258 -0.5773502691896258 -0.5773502691896258
  0.5773502691896258 -0.5773502691896258  0.5773502691896258 -0.5773502691896258
 -0.5773502691896258 -0.5773502691896258  0.5773502691896258 -0.5773502691896258
 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258
  0.5773502691896258 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258
 

If you drop the offset from each line (the last number), each line is the Voronoi vertex for the corresponding facet. The neighboring facets for each point define the Voronoi region for each point. For example:

 rbox d G1 | qconvex FN
 6
 4 7 3 2 6
 4 5 0 1 4
 4 7 4 5 6
 4 3 1 0 2
 4 6 2 0 5
 4 7 3 1 4
 

The Voronoi vertices {7, 3, 2, 6} define the Voronoi region for point 0. Point 0 is [0,0,-1]. Its Voronoi vertices are

 -0.5773502691896258  0.5773502691896258 -0.5773502691896258
  0.5773502691896258  0.5773502691896258 -0.5773502691896258
 -0.5773502691896258 -0.5773502691896258 -0.5773502691896258
  0.5773502691896258 -0.5773502691896258 -0.5773502691896258
 

In this case, the Voronoi vertices are oriented, but in general they are unordered.

By taking the dual of the Delaunay triangulation, you can construct the Voronoi diagram. For cospherical points, the convex hull vertices for each facet, define the input sites for each Voronoi vertex. In 3-d, the input sites are oriented. For example:

 rbox d G1 | qconvex i
 8
 3 1 4
 1 3 5
 0 3 4
 3 0 5
 2 1 5
 1 2 4
 2 0 4
 0 2 5
 

The convex hull vertices for facet 0 are {3, 1, 4}. So Voronoi vertex 0 (i.e., [-0.577, 0.577, 0.577]) is the Voronoi vertex for input sites {3, 1, 4} (i.e., {[0,1,0], [0,0,1], [-1,0,0]}).

»Can Qhull compute the unbounded rays of the Voronoi diagram?

Use 'Fo' to compute the separating hyperplanes for unbounded Voronoi regions. The corresponding ray goes to infinity from the Voronoi vertices. If you enclose the input sites in a large enough box, the outermost bounded regions will represent the unbounded regions of the original points.

If you do not box the input sites, you can identify the unbounded regions. They list '0' as a vertex. Vertex 0 represents "infinity". Each unbounded ray includes vertex 0 in option 'Fv. See Voronoi graphics and Voronoi notes.

»Approximation questions

»How do I approximate data with a simplex

Qhull may be used to help select a simplex that approximates a data set. It will take experimentation. Geomview will help to visualize the results. This task may be difficult to do in 5-d and higher. Use rbox options 'x' and 'y' to produce random distributions within a simplex. Your methods work if you can recover the simplex.

Use Qhull's precision options to get a first approximation to the hull, say with 10 to 50 facets. For example, try 'C0.05' to remove small facets after constructing the hull. Use 'W0.05' to ignore points within 0.05 of a facet. Use 'PA5' to print the five largest facets by area.

Then use other methods to fit a simplex to this data. Remove outlying vertices with few nearby points. Look for large facets in different quadrants. You can use option 'Pd0d1d2' to print all the facets in a quadrant.

In 4-d and higher, use the outer planes (option 'Fo' or 'facet->maxoutside') since the hyperplane of an approximate facet may be below many of the input points.

For example, consider fitting a cube to 1000 uniformly random points in the unit cube. In this case, the first try was good:

 rbox 1000 | qconvex W0.05 C0.05 PA6 Fo
 4
 6
 0.35715408374381 0.08706467018177928 -0.9299788727015564 -0.5985514741284483
 0.995841591359023 -0.02512604712761577 0.08756829720435189 -0.5258834069202866
 0.02448099521570909 -0.02685210459017302 0.9993396046151313 -0.5158104982631999
 -0.9990223929415094 -0.01261133513150079 0.04236994958247349 -0.509218270408407
 -0.0128069014364698 -0.9998380680115362 0.01264203427283151 -0.5002512653670584
 0.01120895057872914 0.01803671994177704 -0.9997744926535512 -0.5056824072956361
 

»Halfspace questions

»How do I compute the intersection of halfspaces with Qhull?

Qhull computes the halfspace intersection about a point. The point must be inside all of the halfspaces. Given a point, a duality turns a halfspace intersection problem into a convex hull problem.

Use linear programming if you do not know a point in the interior of the halfspaces. See the manual. You will need a linear programming code. This may require a fair amount of work to implement.

»Qhull library questions

»Is Qhull available for Mathematica, Matlab, or Maple?

MATLAB

Z. You of MathWorks added qhull to MATLAB 6. See functions convhulln, delaunayn, griddata3, griddatan, tsearch, tsearchn, and voronoin. V. Brumberg update MATLAB R14 for Qhull 2003.1 and triangulated output.

Engwirda wrote mesh2d for unstructured mesh generation in MATLAB. It is based on the iterative method of Persson and generally results in better quality meshes than delaunay refinement.

Mathematica and Maple

See qh-math for a Delaunay interface to Mathematica. It includes projects for CodeWarrior on the Macintosh and Visual C++ on Win32 PCs.

See Mathematica ('m') and Maple ('FM') output options.

»Why are there too few ridges?

The following sample code may produce fewer ridges than expected:
   facetT *facetp;
   ridgeT *ridge, **ridgep;
 
   FORALLfacets {
     printf("facet f%d\n", facet->id);
     FOREACHridge_(facet->ridges) {
       printf("   ridge r%d between f%d and f%d\n", ridge->id, ridge->top->id, ridge->bottom->id);
     }
   }
 

Qhull does not create ridges for simplicial facets. Instead it computes ridges from facet->neighbors. To make ridges for a simplicial facet, use qh_makeridges() in merge.c. Usefacet->visit_id to visit each ridge once (instead of twice). For example,

   facetT *facet, *neighbor;
   ridgeT *ridge, **ridgep;
 
   qh visit_id++;
   FORALLfacets {
     printf("facet f%d\n", facet->id);
     qh_makeridges(facet);
     facet->visitId= qh visit_id;
     FOREACHridge_(facet->ridges) {
         neighbor= otherfacet_(ridge, visible);
         if (neighbor->visitid != qh visit_id)
             printf("   ridge r%d between f%d and f%d\n", ridge->id, ridge->top->id, ridge->bottom->id);
     }
   }
 

»Can Qhull use coordinates without placing them in a data file?

Use qh_call_qhull(). See user_eg.c for an example. See the manual for an introduction to the Qhull library.

Start with a small example for which you know the answer.

»How large are Qhull's data structures?

Qhull uses a general-dimension data structure. The size depends on the dimension. Use option 'Ts' to print out the memory statistics [e.g., 'rbox D2 10 | qconvex Ts'].

»Can Qhull construct convex hulls and Delaunay triangulations one point at a time?

The Qhull library may be used to construct convex hulls and Delaunay triangulations one point at a time. It may not be used for deleting points or moving points.

Qhull is designed for batch processing. Neither Clarkson's randomized incremental algorithm nor Qhull are designed for on-line operation. For many applications, it is better to reconstruct the convex hull or Delaunay triangulation from scratch for each new point.

With random point sets and on-line processing, Clarkson's algorithm should run faster than Qhull. Clarkson uses the intermediate facets to reject new, interior points, while Qhull, when used on-line, visits every facet to reject such points. If used on-line for n points, Clarkson may take O(n) times as much memory as the average off-line case, while Qhull's space requirement does not change.

If you triangulate the output before adding all the points (option 'Qt' and procedure qh_triangulate), you must set option 'Q11'. It duplicates the normals of triangulated facets and recomputes the centrums. This should be avoided for regular use since triangulated facets are not clearly convex with their neighbors. It appears to work most of the time, but fails for cases that Qhull normally handles well [see the test call to qh_triangulate in qh_addpoint].

»How do I visit the ridges of a Delaunay triangulation?

To visit the ridges of a Delaunay triangulation, visit each facet. Each ridge will appear twice since it belongs to two facets. In pseudo-code:

     for each facet of the triangulation
         if the facet is Delaunay (i.e., part of the lower convex hull)
             for each ridge of the facet
                 if the ridge's neighboring facet has not been visited
                     ... process a ridge of the Delaunay triangulation ...
 

In undebugged, C code:

     qh visit_id++;
     FORALLfacets_(facetlist)
         if (!facet->upperdelaunay) {
             facet->visitid= qh visit_id;
             qh_makeridges(facet);
             FOREACHridge_(facet->ridges) {
                 neighbor= otherfacet_(ridge, facet);
                 if (neighbor->visitid != qh visit_id) {
                     /* Print ridge here with facet-id and neighbor-id */
                     /*fprintf(fp, "f%d\tf%d\t",facet->id,neighbor->ID);*/
                     FOREACHvertex_(ridge->vertices)
                         fprintf(fp,"%d ",qh_pointid (vertex->point) );
                     qh_printfacetNvertex_simplicial (fp, facet, format);
                     fprintf(fp," ");
                     if(neighbor->upperdelaunay)
                         fprintf(fp," -1 -1 -1 -1 ");
                     else
                         qh_printfacetNvertex_simplicial (fp, neighbor, format);
                     fprintf(fp,"\n");
                 }
             }
         }
     }
 

Qhull should be redesigned as a class library, or at least as an API. It currently provides everything needed, but the programmer has to do a lot of work. Hopefully someone will write C++ wrapper classes or a Python module for Qhull.

»How do I visit the Delaunay regions?

Qhull constructs a Delaunay triangulation by lifting the input sites to a paraboloid. The Delaunay triangulation corresponds to the lower convex hull of the lifted points. To visit each facet of the lower convex hull, use:

     facetT *facet;
 
     ...
     FORALLfacets {
         if (!facet->upperdelaunay) {
             ... only facets for Delaunay regions ...
         }
     }
 

»When is a point outside or inside a facet?

A point is outside of a facet if it is clearly outside the facet's outer plane. The outer plane is defined by an offset (facet->maxoutside) from the facet's hyperplane.

     facetT *facet;
     pointT *point;
     realT dist;
 
     ...
     qh_distplane(point, facet, &dist);
     if (dist > facet->maxoutside + 2 * qh DISTround) {
         /* point is clearly outside of facet */
     }
 

A point is inside of a facet if it is clearly inside the facet's inner plane. The inner plane is computed as the maximum distance of a vertex to the facet. It may be computed for an individual facet, or you may use the maximum over all facets. For example:

     facetT *facet;
     pointT *point;
     realT dist;
 
     ...
     qh_distplane(point, facet, &dist);
     if (dist < qh min_vertex - 2 * qh DISTround) {
         /* point is clearly inside of facet */
     }
 

Both tests include two qh.DISTrounds because the computation of the furthest point from a facet may be off by qh.DISTround and the computation of the current distance to the facet may be off by qh.DISTround.

»How do I find the facet that is closest to a point?

Use qh_findbestfacet(). For example,

     coordT point[ DIM ];
     boolT isoutside;
     realT bestdist;
     facetT *facet;
 
     ... set coordinates for point ...
 
     facet= qh_findbestfacet (point, qh_ALL, &bestdist, &isoutside);
 
     /* 'facet' is the closest facet to 'point' */
 

qh_findbestfacet() performs a directed search for the facet furthest below the point. If the point lies inside this facet, qh_findbestfacet() performs an exhaustive search of all facets. An exhaustive search may be needed because a facet on the far side of a lens-shaped distribution may be closer to a point than all of the facet's neighbors. The exhaustive search may be skipped for spherical distributions.

Also see, "How do I find the Delaunay triangle that is closest to a point?"

»How do I find the Delaunay triangle or Voronoi region that is closest to a point?

A Delaunay triangulation subdivides the plane, or in general dimension, subdivides space. Given a point, how do you determine the subdivision containing the point? Or, given a set of points, how do you determine the subdivision containing each point of the set? Efficiency is important -- an exhaustive search of the subdivision is too slow.

First compute the Delaunay triangle with qh_call_qhull(). Lift the point to the paraboloid by summing the squares of the coordinates. Use qh_findbestfacet() [poly2.c] to find the closest Delaunay triangle. Determine the closest vertex to find the corresponding Voronoi region. Do not use options 'Qbb', 'QbB', 'Qbk:n', or 'QBk:n' since these scale the last coordinate. Optimizations of qh_findbestfacet() should be possible for Delaunay triangulations.

You first need to lift the point to the paraboloid (i.e., the last coordinate is the sum of the squares of the point's coordinates). The routine, qh_setdelaunay() [geom2.c], lifts an array of points to the paraboloid. The following excerpt is from findclosest() in user_eg.c.

     coordT point[ DIM + 1];  /* one extra coordinate for lifting the point */
     boolT isoutside;
     realT bestdist;
     facetT *facet;
 
     ... set coordinates for point[] ...
 
     qh_setdelaunay (DIM+1, 1, point);
     facet= qh_findbestfacet (point, qh_ALL, &bestdist, &isoutside);
     /* 'facet' is the closest Delaunay triangle to 'point' */
 

The returned facet either contains the point or it is the closest Delaunay triangle along the convex hull of the input set.

Point location is an active research area in Computational Geometry. For a practical approach, see Mucke, et al, "Fast randomized point location without preprocessing in two- and three-dimensional Delaunay triangulations," Computational Geometry '96, p. 274-283, May 1996. For an introduction to planar point location see [O'Rourke '93]. Also see, "How do I find the facet that is closest to a point?"

To locate the closest Voronoi region, determine the closest vertex of the closest Delaunay triangle.

     realT dist, bestdist= REALmax;
         vertexT *bestvertex= NULL, *vertex, **vertexp;
 
     /* 'facet' is the closest Delaunay triangle to 'point' */
 
     FOREACHvertex_( facet->vertices ) {
         dist= qh_pointdist( point, vertex->point, DIM );
         if (dist < bestdist) {
             bestdist= dist;
             bestvertex= vertex;
         }
     }
     /* 'bestvertex' represents the Voronoi region closest to 'point'.  The corresponding
        input site is 'bestvertex->point' */
 

»How do I list the vertices?

To list the vertices (i.e., extreme points) of the convex hull use

     vertexT *vertex;
 
     FORALLvertices {
       ...
       // vertex->point is the coordinates of the vertex
       // qh_pointid(vertex->point) is the point ID of the vertex
       ...
     }
     

»How do I test code that uses the Qhull library?

Compare the output from your program with the output from the Qhull program. Use option 'T1' or 'T4' to trace what Qhull is doing. Prepare a small example for which you know the output. Run the example through the Qhull program and your code. Compare the trace outputs. If you do everything right, the two trace outputs should be almost the same. The trace output will also guide you to the functions that you need to review.

»When I compute a plane equation from a facet, I sometimes get an outward-pointing normal and sometimes an inward-pointing normal

Qhull orients simplicial facets, and prints oriented output for 'i', 'Ft', and other options. The orientation depends on both the vertex order and the flag facet->toporient.

Qhull does not orient non-simplicial facets. Instead it orients the facet's ridges. These are printed with the 'Qt' and 'Ft' option. The facet's hyperplane is oriented.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: FAQ: Table of Contents


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-impre.htm b/html/qh-impre.htm index 294ef9a..c5ff209 100644 --- a/html/qh-impre.htm +++ b/html/qh-impre.htm @@ -1,797 +1,797 @@ Imprecision in Qhull

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull imprecision: Table of Contents (please wait while loading)


[4-d cube] Imprecision in Qhull

This section of the Qhull manual discusses the problems caused by coplanar points and why Qhull uses options 'C-0' or 'Qx' by default. If you ignore precision issues with option 'Q0', the output from Qhull can be arbitrarily bad. Qhull avoids precision problems if you merge facets (the default) or joggle the input ('QJ').

Use option 'Tv' to verify the output from Qhull. It verifies that adjacent facets are clearly convex. It verifies that all points are on or below all facets.

Qhull automatically tests for convexity if it detects precision errors while constructing the hull.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»Qhull imprecision: Table of Contents


»Precision problems

Since Qhull uses floating point arithmetic, roundoff error occurs with each calculation. This causes problems for geometric algorithms. Other floating point codes for convex hulls, Delaunay triangulations, and Voronoi diagrams also suffer from these problems. Qhull handles most of them.

There are several kinds of precision errors:

  • Representation error occurs when there are not enough digits to represent a number, e.g., 1/3.
  • Measurement error occurs when the input coordinates are from measurements.
  • Roundoff error occurs when a calculation is rounded to a fixed number of digits, e.g., a floating point calculation.
  • Approximation error occurs when the user wants an approximate result because the exact result contains too much detail.

Under imprecision, calculations may return erroneous results. For example, roundoff error can turn a small, positive number into a small, negative number. See Milenkovic ['93] for a discussion of strict robust geometry. Qhull does not meet Milenkovic's criterion for accuracy. Qhull's error bound is empirical instead of theoretical.

Qhull 1.0 checked for precision errors but did not handle them. The output could contain concave facets, facets with inverted orientation ("flipped" facets), more than two facets adjacent to a ridge, and two facets with exactly the same set of vertices.

Qhull 2.4 and later automatically handles errors due to machine round-off. Option 'C-0' or 'Qx' is set by default. In 5-d and higher, the output is clearly convex but an input point could be outside of the hull. This may be corrected by using option 'C-0', but then the output may contain wide facets.

Qhull 2.5 and later provides option 'QJ' to joggled input. Each input coordinate is modified by a small, random quantity. If a precision error occurs, a larger modification is tried. When no precision errors occur, Qhull is done.

Qhull 3.1 and later provides option 'Qt' for triangulated output. This removes the need for joggled input ('QJ'). Non-simplicial facets are triangulated. The facets may have zero area. Triangulated output is particularly useful for Delaunay triangulations.

By handling round-off errors, Qhull can provide a variety of output formats. For example, it can return the halfspace that defines each facet ('n'). The halfspaces include roundoff error. If the halfspaces were exact, their intersection would return the original extreme points. With imprecise halfspaces and exact arithmetic, nearly incident points may be returned for an original extreme point. By handling roundoff error, Qhull returns one intersection point for each of the original extreme points. Qhull may split or merge an extreme point, but this appears to be unlikely.

The following pipe implements the identity function for extreme points (with roundoff):

qconvex FV n | qhalf Fp

Bernd Gartner published his Miniball algorithm ["Fast and robust smallest enclosing balls", Algorithms - ESA '99, LNCS 1643]. It uses floating point arithmetic and a carefully designed primitive operation. It is practical to 20-D or higher, and identifies at least two points on the convex hull of the input set. Like Qhull, it is an incremental algorithm that processes points furthest from the intermediate result and ignores points that are close to the intermediate result.

»Merged facets or joggled input

This section discusses the choice between merged facets and joggled input. By default, Qhull uses merged facets to handle precision problems. With option 'QJ', the input is joggled. See examples of joggled input and triangulated output.

  • Use merged facets (the default) when you want non-simplicial output (e.g., the faces of a cube).
  • Use merged facets and triangulated output ('Qt') when you want simplicial output and coplanar facets (e.g., triangles for a Delaunay triangulation).
  • Use joggled input ('QJ') when you need clearly-convex, simplicial output.

The choice between merged facets and joggled input depends on the application. Both run about the same speed. Joggled input may be faster if the initial joggle is sufficiently large to avoid precision errors.

Most applications should used merged facets with triangulated output.

Use merged facets (the default, 'C-0') or triangulated output ('Qt') if

  • Your application supports non-simplicial facets, or it allows degenerate, simplicial facets (option 'Qt').
  • You do not want the input modified.
  • You want to set additional options for approximating the hull.
  • You use single precision arithmetic (realT).

Use joggled input ('QJ') if

  • Your application needs clearly convex, simplicial output
  • Your application supports perturbed input points and narrow triangles.
  • Seven significant digits is sufficient accuracy.

You may use both techniques or combine joggle with post-merging ('Cn').

Other researchers have used techniques similar to joggled input. Sullivan and Beichel [ref?] randomly perturb the input before computing the Delaunay triangulation. Corkum and Wyllie [news://comp.graphics, 1990] randomly rotate a polytope before testing point inclusion. Edelsbrunner and Mucke [Symp. Comp. Geo., 1988] and Yap [J. Comp. Sys. Sci., 1990] symbolically perturb the input to remove singularities.

Merged facets ('C-0') handles precision problems directly. If a precision problem occurs, Qhull merges one of the offending facets into one of its neighbors. Since all precision problems in Qhull are associated with one or more facets, Qhull will either fix the problem or attempt to merge the last remaining facets.

»Delaunay triangulations

Programs that use Delaunay triangulations traditionally assume a triangulated input. By default, qdelaunay merges regions with cocircular or cospherical input sites. If you want a simplicial triangulation use triangulated output ('Qt') or joggled input ('QJ').

For Delaunay triangulations, triangulated output should produce good results. All points are within roundoff error of a paraboloid. If two points are nearly incident, one will be a coplanar point. So all points are clearly separated and convex. If qhull reports deleted vertices, the triangulation may contain serious precision faults. Deleted vertices are reported in the summary ('s', 'Fs'

You should use option 'Qbb' with Delaunay triangulations. It scales the last coordinate and may reduce roundoff error. It is automatically set for qdelaunay, qvoronoi, and option 'QJ'.

Edelsbrunner, H, Geometry and Topology for Mesh Generation, Cambridge University Press, 2001. Good mathematical treatise on Delaunay triangulation and mesh generation for 2-d and 3-d surfaces. The chapter on surface simplification is particularly interesting. It is similar to facet merging in Qhull.

Veron and Leon published an algorithm for shape preserving polyhedral simplification with bounded error [Computers and Graphics, 22.5:565-585, 1998]. It remove nodes using front propagation and multiple remeshing.

»Halfspace intersection

The identity pipe for Qhull reveals some precision questions for halfspace intersections. The identity pipe creates the convex hull of a set of points and intersects the facets' hyperplanes. It should return the input points, but narrow distributions may drop points while offset distributions may add points. It may be better to normalize the input set about the origin. For example, compare the first results with the later two results: [T. Abraham]

rbox 100 s t | tee r | qconvex FV n | qhalf Fp | cat - r | /bin/sort -n | tail
rbox 100 L1e5 t | tee r | qconvex FV n | qhalf Fp | cat - r | /bin/sort -n | tail
rbox 100 s O10 t | tee r | qconvex FV n | qhalf Fp | cat - r | /bin/sort -n | tail

»Merged facets

Qhull detects precision problems when computing distances. A precision problem occurs if the distance computation is less than the maximum roundoff error. Qhull treats the result of a hyperplane computation as if it were exact.

Qhull handles precision problems by merging non-convex facets. The result of merging two facets is a thick facet defined by an inner plane and an outer plane. The inner and outer planes are offsets from the facet's hyperplane. The inner plane is clearly below the facet's vertices. At the end of Qhull, the outer planes are clearly above all input points. Any exact convex hull must lie between the inner and outer planes.

Qhull tests for convexity by computing a point for each facet. This point is called the facet's centrum. It is the arithmetic center of the facet's vertices projected to the facet's hyperplane. For simplicial facets with d vertices, the centrum is equivalent to the centroid or center of gravity.

Two neighboring facets are convex if each centrum is clearly below the other hyperplane. The 'Cn' or 'C-n' options sets the centrum's radius to n . A centrum is clearly below a hyperplane if the computed distance from the centrum to the hyperplane is greater than the centrum's radius plus two maximum roundoff errors. Two are required because the centrum can be the maximum roundoff error above its hyperplane and the distance computation can be high by the maximum roundoff error.

With the 'C-n' or 'A-n ' options, Qhull merges non-convex facets while constructing the hull. The remaining facets are clearly convex. With the 'Qx ' option, Qhull merges coplanar facets after constructing the hull. While constructing the hull, it merges coplanar horizon facets, flipped facets, concave facets and duplicated ridges. With 'Qx', coplanar points may be missed, but it appears to be unlikely.

If the user sets the 'An' or 'A-n' option, then all neighboring facets are clearly convex and the maximum (exact) cosine of an angle is n.

If 'C-0' or 'Qx' is used without other precision options (default), Qhull tests vertices instead of centrums for adjacent simplices. In 3-d, if simplex abc is adjacent to simplex bcd, Qhull tests that vertex a is clearly below simplex bcd , and vertex d is clearly below simplex abc. When building the hull, Qhull tests vertices if the horizon is simplicial and no merges occur.

»How Qhull merges facets

If two facets are not clearly convex, then Qhull removes one or the other facet by merging the facet into a neighbor. It selects the merge which minimizes the distance from the neighboring hyperplane to the facet's vertices. Qhull also performs merges when a facet has fewer than d neighbors (called a degenerate facet), when a facet's vertices are included in a neighboring facet's vertices (called a redundant facet), when a facet's orientation is flipped, or when a ridge occurs between more than two facets.

Qhull performs merges in a series of passes sorted by merge angle. Each pass merges those facets which haven't already been merged in that pass. After a pass, Qhull checks for redundant vertices. For example, if a vertex has only two neighbors in 3-d, the vertex is redundant and Qhull merges it into an adjacent vertex.

Merging two simplicial facets creates a non-simplicial facet of d+1 vertices. Additional merges create larger facets. When merging facet A into facet B, Qhull retains facet B's hyperplane. It merges the vertices, neighbors, and ridges of both facets. It recomputes the centrum if a wide merge has not occurred (qh_WIDEcoplanar) and the number of extra vertices is smaller than a constant (qh_MAXnewcentrum).

»Limitations of merged facets

  • Uneven dimensions -- If one coordinate has a larger absolute value than other coordinates, it may dominate the effect of roundoff errors on distance computations. You may use option 'QbB' to scale points to the unit cube. For Delaunay triangulations and Voronoi diagrams, qdelaunay and qvoronoi always set option 'Qbb'. It scales the last coordinate to [0,m] where m is the maximum width of the other coordinates. Option 'Qbb' is needed for Delaunay triangulations of integer coordinates and nearly cocircular points.

    For example, compare

             rbox 1000 W0 t | qconvex Qb2:-1e-14B2:1e-14
     
    with
             rbox 1000 W0 t | qconvex
     
    The distributions are the same but the first is compressed to a 2e-14 slab.

  • Post-merging of coplanar facets -- In 5-d and higher, option 'Qx' (default) delays merging of coplanar facets until post-merging. This may allow "dents" to occur in the intermediate convex hulls. A point may be poorly partitioned and force a poor approximation. See option 'Qx' for further discussion.

    This is difficult to produce in 5-d and higher. Option 'Q6' turns off merging of concave facets. This is similar to 'Qx'. It may lead to serious precision errors, for example,

             rbox 10000 W1e-13  | qhull Q6  Tv
     

  • Maximum facet width -- Qhull reports the maximum outer plane and inner planes (if more than roundoff error apart). There is no upper bound for either figure. This is an area for further research. Qhull does a good job of post-merging in all dimensions. Qhull does a good job of pre-merging in 2-d, 3-d, and 4-d. With the 'Qx' option, it does a good job in higher dimensions. In 5-d and higher, Qhull does poorly at detecting redundant vertices.

    In the summary ('s'), look at the ratio between the maximum facet width and the maximum width of a single merge, e.g., "(3.4x)". Qhull usually reports a ratio of four or lower in 3-d and six or lower in 4-d. If it reports a ratio greater than 10, this may indicate an implementation error. Narrow distributions (see following) may produce wide facets.

    For example, if special processing for narrow distributions is turned off ('Q10'), qhull may produce a wide facet:

              RBOX 1000 L100000 s G1e-16 t1002074964 | QHULL Tv Q10
     

  • Narrow distribution -- In 3-d, a narrow distribution may result in a poor approximation. For example, if you do not use qdelaunay nor option 'Qbb', the furthest-site Delaunay triangulation of nearly cocircular points may produce a poor approximation:
              RBOX s 5000 W1e-13 D2 t1002151341 | QHULL d Qt
              RBOX 1000 s W1e-13 t1002231672 | QHULL d Tv
     

    During construction of the hull, a point may be above two facets with opposite orientations that span the input set. Even though the point may be nearly coplanar with both facets, and can be distant from the precise convex hull of the input sites. Additional facets leave the point distant from a facet. To fix this problem, add option 'Qbb' (it scales the last coordinate). Option 'Qbb' is automatically set for qdelaunay and qvoronoi.

    Qhull generates a warning if the initial simplex is narrow. For narrow distributions, Qhull changes how it processes coplanar points -- it does not make a point coplanar until the hull is finished. Use option 'Q10' to try Qhull without special processing for narrow distributions. For example, special processing is needed for:

              RBOX 1000 L100000 s G1e-16 t1002074964 | QHULL Tv Q10
     

    You may turn off the warning message by reducing qh_WARNnarrow in user.h or by setting option 'Pp'.

    Similar problems occur for distributions with a large flat facet surrounded with many small facet at a sharp angle to the large facet. Qhull 3.1 fixes most of these problems, but a poor approximation can occur. A point may be left outside of the convex hull ('Tv'). Examples include the furthest-site Delaunay triangulation of nearly cocircular points plus the origin, and the convex hull of a cone of nearly cocircular points. The width of the band is 10^-13.

             rbox s 1000 W1e-13 P0 D2 t996799242 | qhull d Tv
             rbox 1000 s Z1 G1e-13 t1002152123 | qhull Tv
             RBOX 1000 s Z1 G1e-13 t1002231668 | QHULL Tv
     

  • Quadratic running time -- If the output contains large, non-simplicial facets, the running time for Qhull may be quadratic in the size of the triangulated output. For example, RBOX 1000 s W1e-13 c G2 | QHULL d is 4 times faster for 500 points. The convex hull contains two large nearly spherical facets and many nearly coplanar facets. Each new point retriangulates the spherical facet and repartitions the remaining points into all of the nearly coplanar facets. In this case, quadratic running time is avoided if you use qdelaunay, add option 'Qbb', or add the origin ('P0') to the input.

  • Facet with zero-area -- It is possible for a zero-area facet to be convex with its neighbors. This can occur if the hyperplanes of neighboring facets are above the facet's centrum, and the facet's hyperplane is above the neighboring centrums. Qhull computes the facet's hyperplane so that it passes through the facet's vertices. The vertices can be collinear.

  • No more facets -- Qhull reports an error if there are d+1 facets left and two of the facets are not clearly convex. This typically occurs when the convexity constraints are too strong or the input points are degenerate. The former is more likely in 5-d and higher -- especially with option 'C-n'.

  • Deleted cone -- Lots of merging can end up deleting all of the new facets for a point. This is a rare event that has only been seen while debugging the code.

  • Triangulated output leads to precision problems -- With sufficient merging, the ridges of a non-simplicial facet may have serious topological and geometric problems. A ridge may be between more than two neighboring facets. If so, their triangulation ('Qt') will fail since two facets have the same vertex set. Furthermore, a triangulated facet may have flipped orientation compared to its neighbors.
  • The triangulation process detects degenerate facets with only two neighbors. These are marked degenerate. They have zero area.

  • Coplanar points -- Option 'Qc' is determined by qh_check_maxout() after constructing the hull. Qhull needs to retain all possible coplanar points in the facets' coplanar sets. This depends on qh_RATIOnearInside in user.h. Furthermore, the cutoff for a coplanar point is arbitrarily set at the minimum vertex. If coplanar points are important to your application, remove the interior points by hand (set 'Qc Qi') or make qh_RATIOnearInside sufficiently large.

  • Maximum roundoff error -- Qhull computes the maximum roundoff error from the maximum coordinates of the point set. Usually the maximum roundoff error is a reasonable choice for all distance computations. The maximum roundoff error could be computed separately for each point or for each distance computation. This is expensive and it conflicts with option 'C-n'.

  • All flipped or upper Delaunay -- When a lot of merging occurs for Delaunay triangulations, a new point may lead to no good facets. For example, try a strong convexity constraint:
             rbox 1000 s t993602376 | qdelaunay C-1e-3
     

»Joggled input

Joggled input is a simple work-around for precision problems in computational geometry ["joggle: to shake or jar slightly," Amer. Heritage Dictionary]. Other names are jostled input or random perturbation. Qhull joggles the input by modifying each coordinate by a small random quantity. If a precision problem occurs, Qhull joggles the input with a larger quantity and the algorithm is restarted. This process continues until no precision problems occur. Unless all inputs incur precision problems, Qhull will terminate. Qhull adjusts the inner and outer planes to account for the joggled input.

Neither joggle nor merged facets has an upper bound for the width of the output facets, but both methods work well in practice. Joggled input is easier to justify. Precision errors occur when the points are nearly singular. For example, four points may be coplanar or three points may be collinear. Consider a line and an incident point. A precision error occurs if the point is within some epsilon of the line. Now joggle the point away from the line by a small, uniformly distributed, random quantity. If the point is changed by more than epsilon, the precision error is avoided. The probability of this event depends on the maximum joggle. Once the maximum joggle is larger than epsilon, doubling the maximum joggle will halve the probability of a precision error.

With actual data, an analysis would need to account for each point changing independently and other computations. It is easier to determine the probabilities empirically ('TRn') . For example, consider computing the convex hull of the unit cube centered on the origin. The arithmetic has 16 significant decimal digits.

Convex hull of unit cube

joggle error prob.
1.0e-15 0.983
2.0e-15 0.830
4.0e-15 0.561
8.0e-15 0.325
1.6e-14 0.185
3.2e-14 0.099
6.4e-14 0.051
1.3e-13 0.025
2.6e-13 0.010
5.1e-13 0.004
1.0e-12 0.002
2.0e-12 0.001

A larger joggle is needed for multiple points. Since the number of potential singularities increases, the probability of one or more precision errors increases. Here is an example.

Convex hull of 1000 points on unit cube

joggle error prob.
1.0e-12 0.870
2.0e-12 0.700
4.0e-12 0.450
8.0e-12 0.250
1.6e-11 0.110
3.2e-11 0.065
6.4e-11 0.030
1.3e-10 0.010
2.6e-10 0.008
5.1e-09 0.003

Other distributions behave similarly. No distribution should behave significantly worse. In Euclidean space, the probability measure of all singularities is zero. With floating point numbers, the probability of a singularity is non-zero. With sufficient digits, the probability of a singularity is extremely small for random data. For a sufficiently large joggle, all data is nearly random data.

Qhull uses an initial joggle of 30,000 times the maximum roundoff error for a distance computation. This avoids most potential singularities. If a failure occurs, Qhull retries at the initial joggle (in case bad luck occurred). If it occurs again, Qhull increases the joggle by ten-fold and tries again. This process repeats until the joggle is a hundredth of the width of the input points. Qhull reports an error after 100 attempts. This should never happen with double-precision arithmetic. Once the probability of success is non-zero, the probability of success increases about ten-fold at each iteration. The probability of repeated failures becomes extremely small.

Merged facets produces a significantly better approximation. Empirically, the maximum separation between inner and outer facets is about 30 times the maximum roundoff error for a distance computation. This is about 2,000 times better than joggled input. Most applications though will not notice the difference.

»Exact arithmetic

Exact arithmetic may be used instead of floating point. Singularities such as coplanar points can either be handled directly or the input can be symbolically perturbed. Using exact arithmetic is slower than using floating point arithmetic and the output may take more space. Chaining a sequence of operations increases the time and space required. Some operations are difficult to do.

Clarkson's hull program and Shewchuk's triangle program are practical implementations of exact arithmetic.

Clarkson limits the input precision to about fifteen digits. This reduces the number of nearly singular computations. When a determinant is nearly singular, he uses exact arithmetic to compute a precise result.

»Approximating a convex hull

Qhull may be used for approximating a convex hull. This is particularly valuable in 5-d and higher where hulls can be immense. You can use 'Qx C-n' to merge facets as the hull is being constructed. Then use 'Cn' and/or 'An' to merge small facets during post-processing. You can print the n largest facets with option 'PAn'. You can print facets whose area is at least n with option 'PFn'. You can output the outer planes and an interior point with 'FV Fo' and then compute their intersection with 'qhalf'.

To approximate a convex hull in 6-d and higher, use post-merging with 'Wn' (e.g., qhull W1e-1 C1e-2 TF2000). Pre-merging with a convexity constraint (e.g., qhull Qx C-1e-2) often produces a poor approximation or terminates with a simplex. Option 'QbB' may help to spread out the data.

You will need to experiment to determine a satisfactory set of options. Use rbox to generate test sets quickly and Geomview to view the results. You will probably want to write your own driver for Qhull using the Qhull library. For example, you could select the largest facet in each quadrant.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull imprecision: Table of Contents


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-optc.htm b/html/qh-optc.htm index 6ae56aa..0ec9b6d 100644 --- a/html/qh-optc.htm +++ b/html/qh-optc.htm @@ -1,289 +1,289 @@ Qhull precision options

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull precision options

This section lists the precision options for Qhull. These options are indicated by an upper-case letter followed by a number. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Precision options

Most users will not need to set these options. They are best used for approximating a convex hull. They may also be used for testing Qhull's handling of precision errors.

By default, Qhull uses options 'C-0' for 2-d, 3-d and 4-d, and 'Qx' for 5-d and higher. These options use facet merging to handle precision errors. You may also use joggled input 'QJ' to avoid precision problems. For more information see Imprecision in Qhull.

 
General
Cn
centrum radius for post-merging
C-n
centrum radius for pre-merging
An
cosine of maximum angle for post-merging
A-n
cosine of maximum angle for pre-merging
Qx
exact pre-merges (allows coplanar facets)
C-0
handle all precision errors
Wn
min distance above plane for outside points
 
Experimental
Un
max distance below plane for a new, coplanar point
En
max roundoff error for distance computation
Vn
min distance above plane for a visible facet
Rn
randomly perturb computations by a factor of [1-n,1+n]

»A-n - cosine of maximum angle for pre-merging.

Pre-merging occurs while Qhull constructs the hull. It is indicated by 'C-n', 'A-n', or 'Qx'.

If the angle between a pair of facet normals is greater than n, Qhull merges one of the facets into a neighbor. It selects the facet that is closest to a neighboring facet.

For example, option 'A-0.99' merges facets during the construction of the hull. If the cosine of the angle between facets is greater than 0.99, one or the other facet is merged. Qhull accounts for the maximum roundoff error.

If 'A-n' is set without 'C-n', then 'C-0' is automatically set.

In 5-d and higher, you should set 'Qx' along with 'A-n'. It skips merges of coplanar facets until after the hull is constructed and before 'An' and 'Cn' are checked.

»An - cosine of maximum angle for post-merging.

Post merging occurs after the hull is constructed. For example, option 'A0.99' merges a facet if the cosine of the angle between facets is greater than 0.99. Qhull accounts for the maximum roundoff error.

If 'An' is set without 'Cn', then 'C0' is automatically set.

»C-0 - handle all precision errors

Qhull handles precision errors by merging facets. The 'C-0' option handles all precision errors in 2-d, 3-d, and 4-d. It is set by default. It may be used in higher dimensions, but sometimes the facet width grows rapidly. It is usually better to use 'Qx' in 5-d and higher. Use 'QJ' to joggle the input instead of merging facets. Use 'Q0' to turn both options off.

Qhull optimizes 'C-0' ("_zero-centrum") by testing vertices instead of centrums for adjacent simplices. This may be slower in higher dimensions if merges decrease the number of processed points. The optimization may be turned off by setting a small value such as 'C-1e-30'. See How Qhull handles imprecision.

»C-n - centrum radius for pre-merging

Pre-merging occurs while Qhull constructs the hull. It is indicated by 'C-n', 'A-n', or 'Qx'.

The centrum of a facet is a point on the facet for testing facet convexity. It is the average of the vertices projected to the facet's hyperplane. Two adjacent facets are convex if each centrum is clearly below the other facet.

If adjacent facets are non-convex, one of the facets is merged into a neighboring facet. Qhull merges the facet that is closest to a neighboring facet.

For option 'C-n', n is the centrum radius. For example, 'C-0.001' merges facets whenever the centrum is less than 0.001 from a neighboring hyperplane. Qhull accounts for roundoff error when testing the centrum.

In 5-d and higher, you should set 'Qx' along with 'C-n'. It skips merges of coplanar facets until after the hull is constructed and before 'An' and 'Cn' are checked.

»Cn - centrum radius for post-merging

Post-merging occurs after Qhull constructs the hull. It is indicated by 'Cn' or 'An'.

For option 'Cn', n is the centrum radius. For example, 'C0.001' merges facets when the centrum is less than 0.001 from a neighboring hyperplane. Qhull accounts for roundoff error when testing the centrum.

Both pre-merging and post-merging may be defined. If only post-merging is used ('Q0' with 'Cn'), Qhull may fail to produce a hull due to precision errors during the hull's construction.

»En - max roundoff error for distance computations

This allows the user to change the maximum roundoff error computed by Qhull. The value computed by Qhull may be overly pessimistic. If 'En' is set too small, then the output may not be convex. The statistic "max. distance of a new vertex to a facet" (from option 'Ts') is a reasonable upper bound for the actual roundoff error.

»Rn - randomly perturb computations

This option perturbs every distance, hyperplane, and angle computation by up to (+/- n * max_coord). It simulates the effect of roundoff errors. Unless 'En' is explicitly set, it is adjusted for 'Rn'. The command 'qhull Rn' will generate a convex hull despite the perturbations. See the Examples section for an example.

Options 'Rn C-n' have the effect of 'W2n' and 'C-2n'. To use time as the random number seed, use option 'QR-1'.

»Un - max distance for a new, coplanar point

This allows the user to set coplanarity. When pre-merging ('C-n ', 'A-n' or 'Qx'), Qhull merges a new point into any coplanar facets. The default value for 'Un' is 'Vn'.

»Vn - min distance for a visible facet

This allows the user to set facet visibility. When adding a point to the convex hull, Qhull determines all facets that are visible from the point. A facet is visible if the distance from the point to the facet is greater than 'Vn'.

Without merging, the default value for 'Vn' is the roundoff error ('En'). With merging, the default value is the pre-merge centrum ('C-n') in 2-d or 3-d, or three times that in other dimensions. If the outside width is specified with option 'Wn ', the maximum, default value for 'Vn' is 'Wn'.

Qhull warns if 'Vn' is greater than 'Wn' and furthest outside ('Qf') is not selected; this combination usually results in flipped facets (i.e., reversed normals).

»Wn - min distance above plane for outside points

Points are added to the convex hull only if they are clearly outside of a facet. A point is outside of a facet if its distance to the facet is greater than 'Wn'. Without pre-merging, the default value for 'Wn' is 'En '. If the user specifies pre-merging and does not set 'Wn', than 'Wn' is set to the maximum of 'C-n' and maxcoord*(1 - A-n).

This option is good for approximating a convex hull.

Options 'Qc' and 'Qi' use the minimum vertex to distinguish coplanar points from interior points.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-optf.htm b/html/qh-optf.htm index 2edb3bf..8ade336 100644 --- a/html/qh-optf.htm +++ b/html/qh-optf.htm @@ -1,733 +1,733 @@ Qhull format options (F)

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull format options (F)

This section lists the format options for Qhull. These options are indicated by 'F' followed by a letter. See Output, Print, and Geomview for other output options.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Additional input & output formats

These options allow for automatic processing of Qhull output. Options 'i', 'o', 'n', and 'p' may also be used.

Summary and control
FA
compute total area and volume for option 's'
FV
print average vertex (interior point for 'qhalf')
FQ
print command for qhull and input
FO
print options to stderr or stdout
FS
print sizes: total area and volume
Fs
print summary: dim, #points, total vertices and facets, #vertices, #facets, max outer and inner plane
Fd
use format for input (offset first)
FD
use cdd format for normals (offset first)
FM
print Maple output (2-d and 3-d)
Facets, points, and vertices
Fa
print area for each facet
FC
print centrum for each facet
Fc
print coplanar points for each facet
Fx
print extreme points (i.e., vertices) of convex hull.
FF
print facets w/o ridges
FI
print ID for each facet
Fi
print inner planes for each facet
Fm
print merge count for each facet (511 max)
FP
print nearest vertex for coplanar points
Fn
print neighboring facets for each facet
FN
print neighboring facets for each point
Fo
print outer planes for each facet
Ft
print triangulation with added points
Fv
print vertices for each facet
Delaunay, Voronoi, and halfspace
Fx
print extreme input sites of Delaunay triangulation or Voronoi diagram.
Fp
print points at halfspace intersections
Fi
print separating hyperplanes for inner, bounded Voronoi regions
Fo
print separating hyperplanes for outer, unbounded Voronoi regions
Fv
print Voronoi diagram as ridges for each input pair
FC
print Voronoi vertex ("center") for each facet

»Fa - print area for each facet

The first line is the number of facets. The remaining lines are the area for each facet, one facet per line. See 'FA' and 'FS' for computing the total area and volume.

Use 'PAn' for printing the n largest facets. Use option 'PFn' for printing facets larger than n.

For Delaunay triangulations, the area is the area of each Delaunay triangle. For Voronoi vertices, the area is the area of the dual facet to each vertex.

Qhull uses the centrum and ridges to triangulate non-simplicial facets. The area for non-simplicial facets is the sum of the areas for each triangle. It is an approximation of the actual area. The ridge's vertices are projected to the facet's hyperplane. If a vertex is far below a facet (qh_WIDEcoplanar in user.h), the corresponding triangles are ignored.

For non-simplicial facets, vertices are often below the facet's hyperplane. If so, the approximation is less than the actual value and it may be significantly less.

»FA - compute total area and volume for option 's'

With option 'FA', Qhull includes the total area and volume in the summary ('s'). Option 'FS' also includes the total area and volume. If facets are merged, the area and volume are approximations. Option 'FA' is automatically set for options 'Fa', 'PAn', and 'PFn'.

With 'qdelaunay s FA', Qhull computes the total area of the Delaunay triangulation. This equals the volume of the convex hull of the data points. With options 'qdelaunay Qu s FA', Qhull computes the total area of the furthest-site Delaunay triangulation. This equals of the total area of the Delaunay triangulation.

See 'Fa' for further details. Option 'FS' also computes the total area and volume.

»Fc - print coplanar points for each facet

The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of coplanar points followed by the point ids.

By default, option 'Fc' reports coplanar points ('Qc'). You may also use option 'Qi'. Options 'Qi Fc' prints interior points while 'Qci Fc' prints both coplanar and interior points.

Each coplanar point or interior point is assigned to the facet it is furthest above (resp., least below).

Use 'Qc p' to print vertex and coplanar point coordinates. Use 'Fv' to print vertices.

»FC - print centrum or Voronoi vertex for each facet

The output starts with the dimension followed by the number of facets. Then each facet centrum is printed, one per line. For qvoronoi, Voronoi vertices are printed instead.

»Fd - use cdd format for input

The input starts with comments. The first comment is reported in the summary. Data starts after a "begin" line. The next line is the number of points followed by the dimension plus one and "real" or "integer". Then the points are listed with a leading "1" or "1.0". The data ends with an "end" line.

For halfspaces ('qhalf Fd'), the input format is the same. Each halfspace starts with its offset. The signs of the offset and coefficients are the opposite of Qhull's convention. The first two lines of the input may be an interior point in 'FV' format.

»FD - use cdd format for normals

Option 'FD' prints normals ('n', 'Fo', 'Fi') or points ('p') in cdd format. The first line is the command line that invoked Qhull. Data starts with a "begin" line. The next line is the number of normals or points followed by the dimension plus one and "real". Then the normals or points are listed with the offset before the coefficients. The offset for points is 1.0. For normals, the offset and coefficients use the opposite sign from Qhull. The data ends with an "end" line.

»FF - print facets w/o ridges

Option 'FF' prints all fields of all facets (as in 'f') without printing the ridges. This is useful in higher dimensions where a facet may have many ridges. For simplicial facets, options 'FF' and 'f ' are equivalent.

»Fi - print inner planes for each facet

The first line is the dimension plus one. The second line is the number of facets. The remainder is one inner plane per line. The format is the same as option 'n'.

The inner plane is a plane that is below the facet's vertices. It is an offset from the facet's hyperplane. It includes a roundoff error for computing the vertex distance.

Note that the inner planes for Geomview output ('Gi') include an additional offset for vertex visualization and roundoff error.

»Fi - print separating hyperplanes for inner, bounded Voronoi regions

With qvoronoi, 'Fi' prints the separating hyperplanes for inner, bounded regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the number of indices and floats. The first pair of indices indicates an adjacent pair of input sites. The next d floats are the normalized coefficients for the hyperplane, and the last float is the offset. The hyperplane is oriented toward 'QVn' (if defined), or the first input site of the pair.

Use 'Fo' for unbounded regions, and 'Fv' for the corresponding Voronoi vertices.

Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. It will list relevant statistics to stderr. The hyperplane is a perpendicular bisector if the midpoint of the input sites lies on the plane, all Voronoi vertices in the ridge lie on the plane, and the angle between the input sites and the plane is ninety degrees. This is true if all statistics are zero. Roundoff and computation errors make these non-zero. The deviations appear to be largest when the corresponding Delaunay triangles are large and thin; for example, the Voronoi diagram of nearly cospherical points.

»FI - print ID for each facet

Print facet identifiers. These are used internally and listed with options 'f' and 'FF'. Options 'Fn ' and 'FN' use facet identifiers for negative indices.

»Fm - print merge count for each facet

The first line is the number of facets. The remainder is the number of merges for each facet, one per line. At most 511 merges are reported for a facet. See 'PMn' for printing the facets with the most merges.

»FM - print Maple output

Qhull writes a Maple file for 2-d and 3-d convex hulls, 2-d and 3-d halfspace intersections, and 2-d Delaunay triangulations. Qhull produces a 2-d or 3-d plot.

Warning: This option has not been tested in Maple.

[From T. K. Abraham with help from M. R. Feinberg and N. Platinova.] The following steps apply while working within the Maple worksheet environment :

  1. Generate the data and store it as an array . For example, in 3-d, data generated in Maple is of the form : x[i],y[i],z[i]

  2. Create a single variable and assign the entire array of data points to this variable. Use the "seq" command within square brackets as shown in the following example. (The square brackets are essential for the rest of the steps to work.)

    >data:=[seq([x[i],y[i],z[i]],i=1..n)]:# here n is the number of data points

  3. Next we need to write the data to a file to be read by qhull. Before writing the data to a file, make sure that the qhull executable files and the data file lie in the same subdirectory. If the executable files are stored in the "C:\qhull3.1\" subdirectory, then save the file in the same subdirectory, say "C:\qhull3.1\datafile.txt". For the sake of integrity of the data file , it is best to first ensure that the data file does not exist before writing into the data file. This can be done by running a delete command first . To write the data to the file, use the "writedata" and the "writedata[APPEND]" commands as illustrated in the following example :

    >system("del c:\\qhull3.1\\datafile.txt");#To erase any previous versions of the file
    >writedata("c:\\qhull3.1\\datafile.txt ",[3, nops(data)]);#writing in qhull format
    >writedata[APPEND]("c:\\ qhull3.1\\datafile.txt ", data);#writing the data points

  4. Use the 'FM' option to produce Maple output. Store the output as a ".mpl" file. For example, using the file we created above, we type the following (in DOS environment)

    qconvex s FM <datafile.txt >dataplot.mpl

  5. To read 3-d output in Maple, we use the 'read' command followed by a 'display3d' command. For example (in Maple environment):

    >with (plots):
    >read `c:\\qhull3.1\\dataplot.mpl`:#IMPORTANT - Note that the punctuation mark used is ' and NOT '. The correct punctuation mark is the one next to the key for "1" (not the punctuation mark near the enter key)
    > qhullplot:=%:
    > display3d(qhullplot);

For Delaunay triangulation orthogonal projection is better.

For halfspace intersections, Qhull produces the dual convex hull.

See Is Qhull available for Maple? for other URLs.

»Fn - print neighboring facets for each facet

The output starts with the number of facets. Then each facet is printed one per line. Each line is the number of neighbors followed by an index for each neighbor. The indices match the other facet output formats.

For simplicial facets, each neighbor is opposite the corresponding vertex (option 'Fv'). Do not compare to option 'i'. Option 'i' orients facets by reversing the order of two vertices. For non-simplicial facets, the neighbors are unordered.

A negative index indicates an unprinted facet due to printing only good facets ('Pg', qdelaunay, qvoronoi). It is the negation of the facet's ID (option 'FI'). For example, negative indices are used for facets "at infinity" in the Delaunay triangulation.

»FN - print neighboring facets for each point

The first line is the number of points. Then each point is printed, one per line. For unassigned points (either interior or coplanar), the line is "0". For assigned coplanar points ('Qc'), the line is "1" followed by the index of the facet that is furthest below the point. For assigned interior points ('Qi'), the line is "1" followed by the index of the facet that is least above the point. For vertices that do not belong to good facet, the line is "0"

For vertices of good facets, the line is the number of neighboring facets followed by the facet indices. The indices correspond to the other 'F' formats. In 4-d and higher, the facets are sorted by index. In 3-d, the facets are in adjacency order (not oriented).

A negative index indicates an unprinted facet due to printing only good facets (qdelaunay, qvoronoi, 'Pdk', 'Pg'). It is the negation of the facet's ID (' FI'). For example, negative indices are used for facets "at infinity" in the Delaunay triangulation.

For Voronoi vertices, option 'FN' lists the vertices of the Voronoi region for each input site. Option 'FN' lists the regions in site ID order. Option 'FN' corresponds to the second half of option 'o'. To convert from 'FN' to 'o', replace negative indices with zero and increment non-negative indices by one.

If you are using the Qhull library or C++ interface, option 'FN' has the side effect of reordering the neighbors for a vertex

»Fo - print outer planes for each facet

The first line is the dimension plus one. The second line is the number of facets. The remainder is one outer plane per line. The format is the same as option 'n'.

The outer plane is a plane that is above all points. It is an offset from the facet's hyperplane. It includes a roundoff error for computing the point distance. When testing the outer plane (e.g., 'Tv'), another roundoff error should be added for the tested point.

If outer planes are not checked ('Q5') or not computed (!qh_MAXoutside), the maximum, computed outside distance is used instead. This can be much larger than the actual outer planes.

Note that the outer planes for Geomview output ('G') include an additional offset for vertex/point visualization, 'lines closer,' and roundoff error.

»Fo - print separating hyperplanes for outer, unbounded Voronoi regions

With qvoronoi, 'Fo' prints the separating hyperplanes for outer, unbounded regions of the Voronoi diagram. The first line is the number of ridges. Then each hyperplane is printed, one per line. A line starts with the number of indices and floats. The first pair of indices indicates an adjacent pair of input sites. The next d floats are the normalized coefficients for the hyperplane, and the last float is the offset. The hyperplane is oriented toward 'QVn' (if defined), or the first input site of the pair.

Option 'Fo' gives the hyperplanes for the unbounded rays of the unbounded regions of the Voronoi diagram. Each hyperplane goes through the midpoint of the corresponding input sites. The rays are directed away from the input sites.

Use 'Fi' for bounded regions, and 'Fv' for the corresponding Voronoi vertices. Use 'Tv' to verify that the corresponding Voronoi vertices lie on the hyperplane.

»FO - print list of selected options

Lists selected options and default values to stderr. Additional 'FO's are printed to stdout.

»Fp - print points at halfspace intersections

The first line is the number of intersection points. The remainder is one intersection point per line. A intersection point is the intersection of d or more halfspaces from 'qhalf'. It corresponds to a facet of the dual polytope. The "infinity" point [-10.101,-10.101,...] indicates an unbounded intersection.

If [x,y,z] are the dual facet's normal coefficients and b<0 is its offset, the halfspace intersection occurs at [x/-b,y/-b,z/-b] plus the interior point. If b>=0, the halfspace intersection is unbounded.

»FP - print nearest vertex for coplanar points

The output starts with the number of coplanar points. Then each coplanar point is printed one per line. Each line is the point ID of the closest vertex, the point ID of the coplanar point, the corresponding facet ID, and the distance. Sort the lines to list the coplanar points nearest to each vertex.

Use options 'Qc' and/or 'Qi' with 'FP'. Options 'Qc FP' prints coplanar points while 'Qci FP' prints coplanar and interior points. Option 'Qc' is automatically selected if 'Qi' is not selected.

For Delaunay triangulations (qdelaunay or qvoronoi), a coplanar point is nearly incident to a vertex. The distance is the distance in the original point set.

If imprecision problems are severe, Qhull will delete input sites when constructing the Delaunay triangulation. Option 'FP' will list these points along with coincident points.

If there are many coplanar or coincident points and non-simplicial facets are triangulated ('Qt'), option 'FP' may be inefficient. It redetermines the original vertex set for each coplanar point.

»FQ - print command for qhull and input

Prints qhull and input command, e.g., "rbox 10 s | qhull FQ". Option 'FQ' may be repeated multiple times.

»Fs - print summary

The first line consists of number of integers ("10") followed by the:

  • dimension
  • number of points
  • number of vertices
  • number of facets
  • number of vertices selected for output
  • number of facets selected for output
  • number of coplanar points for selected facets
  • number of nonsimplicial or merged facets selected for output
  • number of deleted vertices
  • number of triangulated facets ('Qt')

The second line consists of the number of reals ("2") followed by the:

  • maximum offset to an outer plane
  • minimum offset to an inner plane.
Roundoff and joggle are included.

For Delaunay triangulations and Voronoi diagrams, the number of deleted vertices should be zero. If greater than zero, then the input is highly degenerate and coplanar points are not necessarily coincident points. For example, 'RBOX 1000 s W1e-13 t995138628 | QHULL d Qbb' reports deleted vertices; the input is nearly cospherical.

Later versions of Qhull may produce additional integers or reals.

»FS - print sizes

The first line consists of the number of integers ("0"). The second line consists of the number of reals ("2"), followed by the total facet area, and the total volume. Later versions of Qhull may produce additional integers or reals.

The total volume measures the volume of the intersection of the halfspaces defined by each facet. It is computed from the facet area. Both area and volume are approximations for non-simplicial facets. See option 'Fa ' for further notes. Option 'FA ' also computes the total area and volume.

»Ft - print triangulation

Prints a triangulation with added points for non-simplicial facets. The output is

  • The first line is the dimension
  • The second line is the number of points, the number of facets, and the number of ridges.
  • All of the input points follow, one per line.
  • The centrums follow, one per non-simplicial facet
  • Then the facets follow as a list of point indices preceded by the number of points. The simplices are oriented.

For convex hulls with simplicial facets, the output is the same as option 'o'.

The added points are the centrums of the non-simplicial facets. Except for large facets, the centrum is the average vertex coordinate projected to the facet's hyperplane. Large facets may use an old centrum to avoid recomputing the centrum after each merge. In either case, the centrum is clearly below neighboring facets. See Precision issues.

The new simplices will not be clearly convex with their neighbors and they will not satisfy the Delaunay property. They may even have a flipped orientation. Use triangulated input ('Qt') for Delaunay triangulations.

For Delaunay triangulations with simplicial facets, the output is the same as option 'o' without the lifted coordinate. Since 'Ft' is invalid for merged Delaunay facets, option 'Ft' is not available for qdelaunay or qvoronoi. It may be used with joggled input ('QJ') or triangulated output ('Qt'), for example, rbox 10 c G 0.01 | qhull d QJ Ft

If you add a point-at-infinity with 'Qz', it is printed after the input sites and before any centrums. It will not be used in a Delaunay facet.

»Fv - print vertices for each facet

The first line is the number of facets. Then each facet is printed, one per line. Each line is the number of vertices followed by the corresponding point ids. Vertices are listed in the order they were added to the hull (the last one added is the first listed).

Option 'i' also lists the vertices, but it orients facets by reversing the order of two vertices. Option 'i' triangulates non-simplicial, 4-d and higher facets by adding vertices for the centrums.

»Fv - print Voronoi diagram

With qvoronoi, 'Fv' prints the Voronoi diagram or furthest-site Voronoi diagram. The first line is the number of ridges. Then each ridge is printed, one per line. The first number is the count of indices. The second pair of indices indicates a pair of input sites. The remaining indices list the corresponding ridge of Voronoi vertices. Vertex 0 is the vertex-at-infinity. It indicates an unbounded ray.

All vertices of a ridge are coplanar. If the ridge is unbounded, add the midpoint of the pair of input sites. The unbounded ray is directed from the Voronoi vertices to infinity.

Use 'Fo' for separating hyperplanes of outer, unbounded regions. Use 'Fi' for separating hyperplanes of inner, bounded regions.

Option 'Fv' does not list ridges that require more than one midpoint. For example, the Voronoi diagram of cospherical points lists zero ridges (e.g., 'rbox 10 s | qvoronoi Fv Qz'). Other examples are the Voronoi diagrams of a rectangular mesh (e.g., 'rbox 27 M1,0 | qvoronoi Fv') or a point set with a rectangular corner (e.g., 'rbox P4,4,4 P4,2,4 P2,4,4 P4,4,2 10 | qvoronoi Fv'). Both cases miss unbounded rays at the corners. To determine these ridges, surround the points with a large cube (e.g., 'rbox 10 s c G2.0 | qvoronoi Fv Qz'). The cube needs to be large enough to bound all Voronoi regions of the original point set. Please report any other cases that are missed. If you can formally describe these cases or write code to handle them, please send email to qhull@qhull.org.

»FV - print average vertex

The average vertex is the average of all vertex coordinates. It is an interior point for halfspace intersection. The first line is the dimension and "1"; the second line is the coordinates. For example,

qconvex FV n | qhalf Fp

prints the extreme points of the original point set (roundoff included).

»Fx - print extreme points (vertices) of convex hulls and Delaunay triangulations

The first line is the number of points. The following lines give the index of the corresponding points. The first point is '0'.

In 2-d, the extreme points (vertices) are listed in counterclockwise order (by qh_ORIENTclock in user.h).

In 3-d and higher convex hulls, the extreme points (vertices) are sorted by index. This is the same order as option 'p' when it doesn't include coplanar or interior points.

For Delaunay triangulations, 'Fx' lists the extreme points of the input sites (i.e., the vertices of their convex hull). The points are unordered.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-optg.htm b/html/qh-optg.htm index bc12709..42cba18 100644 --- a/html/qh-optg.htm +++ b/html/qh-optg.htm @@ -1,271 +1,271 @@ Qhull Geomview options (G)

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull Geomview options (G)

This section lists the Geomview options for Qhull. These options are indicated by 'G' followed by a letter. See Output, Print, and Format for other output options. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Geomview output options

Geomview is the graphical viewer for visualizing Qhull output in 2-d, 3-d and 4-d.

Geomview displays each facet of the convex hull. The color of a facet is determined by the coefficients of the facet's normal equation. For imprecise hulls, Geomview displays the inner and outer hull. Geomview can also display points, ridges, vertices, coplanar points, and facet intersections.

For 2-d Delaunay triangulations, Geomview displays the corresponding paraboloid. Geomview displays the 2-d Voronoi diagram. For halfspace intersections, it displays the dual convex hull.

 
General
G
display Geomview output
Gt
display transparent 3-d Delaunay triangulation
GDn
drop dimension n in 3-d and 4-d output
 
 
Specific
Ga
display all points as dots
Gc
display centrums (2-d, 3-d)
Gp
display coplanar points and vertices as radii
Gh
display hyperplane intersections
Gi
display inner planes only (2-d, 3-d)
Go
display outer planes only (2-d, 3-d)
Gr
display ridges (3-d)
Gv
display vertices as spheres
Gn
do not display planes

»G - produce output for viewing with Geomview

By default, option 'G' displays edges in 2-d, outer planes in 3-d, and ridges in 4-d.

A ridge can be explicit or implicit. An explicit ridge is a (d-1)-dimensional simplex between two facets. In 4-d, the explicit ridges are triangles. An implicit ridge is the topological intersection of two neighboring facets. It is the union of explicit ridges.

For non-simplicial 4-d facets, the explicit ridges can be quite complex. When displaying a ridge in 4-d, Qhull projects the ridge's vertices to one of its facets' hyperplanes. Use 'Gh' to project ridges to the intersection of both hyperplanes. This usually results in a cleaner display.

For 2-d Delaunay triangulations, Geomview displays the corresponding paraboloid. Geomview displays the 2-d Voronoi diagram. For halfspace intersections, it displays the dual convex hull.

»Ga - display all points as dots

Each input point is displayed as a green dot.

»Gc - display centrums (3-d)

The centrum is defined by a green radius sitting on a blue plane. The plane corresponds to the facet's hyperplane. If you sight along a facet's hyperplane, you will see that all neighboring centrums are below the facet. The radius is defined by 'C-n' or 'Cn'.

»GDn - drop dimension n in 3-d and 4-d output

The result is a 2-d or 3-d object. In 4-d, this corresponds to viewing the 4-d object from the nth axis without perspective. It's best to view 4-d objects in pieces. Use the 'Pdk' 'Pg' 'PG' 'QGn' and 'QVn' options to select a few facets. If one of the facets is perpendicular to an axis, then projecting along that axis will show the facet exactly as it is in 4-d. If you generate many facets, use Geomview's ginsu module to view the interior

To view multiple 4-d dimensions at once, output the object without 'GDn' and read it with Geomview's ndview. As you rotate the object in one set of dimensions, you can see how it changes in other sets of dimensions.

For additional control over 4-d objects, output the object without 'GDn' and read it with Geomview's 4dview. You can slice the object along any 4-d plane. You can also flip the halfspace that's deleted when slicing. By combining these features, you can get some interesting cross sections.

»Gh - display hyperplane intersections (3-d, 4-d)

In 3-d, the intersection is a black line. It lies on two neighboring hyperplanes, c.f., the blue squares associated with centrums ('Gc '). In 4-d, the ridges are projected to the intersection of both hyperplanes. If you turn on edges (Geomview's 'appearances' menu), each triangle corresponds to one ridge. The ridges may overlap each other.

»Gi - display inner planes only (2-d, 3-d)

The inner plane of a facet is below all of its vertices. It is parallel to the facet's hyperplane. The inner plane's color is the opposite of the outer plane's color, i.e., [1-r,1-g,1-b] . Its edges are determined by the vertices.

»Gn - do not display planes

By default, Geomview displays the precise plane (no merging) or both inner and output planes (if merging). If merging, Geomview does not display the inner plane if the the difference between inner and outer is too small.

»Go - display outer planes only (2-d, 3-d)

The outer plane of a facet is above all input points. It is parallel to the facet's hyperplane. Its color is determined by the facet's normal, and its edges are determined by the vertices.

»Gp - display coplanar points and vertices as radii

Coplanar points ('Qc'), interior points ('Qi'), outside points ('TCn' or 'TVn'), and vertices are displayed as red and yellow radii. The radii are perpendicular to the corresponding facet. Vertices are aligned with an interior point. The radii define a ball which corresponds to the imprecision of the point. The imprecision is the maximum of the roundoff error, the centrum radius, and maxcoord * (1 - A-n). It is at least 1/20'th of the maximum coordinate, and ignores post merging if pre-merging is done.

If 'Gv' (print vertices as spheres) is also selected, option 'Gp' displays coplanar points as radii. Select options Qc' and/or 'Qi'. Options 'Qc Gpv' displays coplanar points while 'Qci Gpv' displays coplanar and interior points. Option 'Qc' is automatically selected if 'Qi' is not selected with options 'Gpv'.

»Gr - display ridges (3-d)

A ridge connects the two vertices that are shared by neighboring facets. It is displayed in green. A ridge is the topological edge between two facets while the hyperplane intersection is the geometric edge between two facets. Ridges are always displayed in 4-d.

»Gt - transparent 3-d Delaunay

A 3-d Delaunay triangulation looks like a convex hull with interior facets. Option 'Gt' removes the outside ridges to reveal the outermost facets. It automatically sets options 'Gr' and 'GDn'. See example eg.17f.delaunay.3.

»Gv - display vertices as spheres (2-d, 3-d)

The radius of the sphere corresponds to the imprecision of the data. See 'Gp' for determining the radius.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-opto.htm b/html/qh-opto.htm index b1be04b..806b117 100644 --- a/html/qh-opto.htm +++ b/html/qh-opto.htm @@ -1,345 +1,345 @@ Qhull output options

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull output options

This section lists the output options for Qhull. These options are indicated by lower case characters. See Formats, Print, and Geomview for other output options.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Output options

Qhull prints its output to standard out. All output is printed text. The default output is a summary (option 's'). Other outputs may be specified as follows.

f
print all fields of all facets
n
print hyperplane normals with offsets
m
print Mathematica output (2-d and 3-d)
o
print OFF file format (dim, points and facets)
s
print summary to stderr
p
print vertex and point coordinates
i
print vertices incident to each facet
 
 
Related options
F
additional input/output formats
G
Geomview output
P
Print options
Ft
print triangulation with added points
 

»f - print all fields of all facets

Print all fields of all facets. The facet is the primary data structure for Qhull.

Option 'f' is for debugging. Most of the fields are available via the 'F' options. If you need specialized information from Qhull, you can use the Qhull library or C++ interface.

Use the 'FF' option to print the facets but not the ridges.

»i - print vertices incident to each facet

The first line is the number of facets. The remaining lines list the vertices for each facet, one facet per line. The indices are 0-relative indices of the corresponding input points. The facets are oriented. Option 'Fv' displays an unoriented list of vertices with a vertex count per line. Options 'o' and 'Ft' displays coordinates for each vertex prior to the vertices for each facet.

Simplicial facets (e.g., triangles in 3-d) consist of d vertices. Non-simplicial facets in 3-d consist of 4 or more vertices. For example, a facet of a cube consists of 4 vertices. Use option 'Qt' to triangulate non-simplicial facets.

For 4-d and higher convex hulls and 3-d and higher Delaunay triangulations, d vertices are listed for all facets. A non-simplicial facet is triangulated with its centrum and each ridge. The index of the centrum is higher than any input point. Use option 'Fv' to list the vertices of non-simplicial facets as is. Use option 'Ft' to print the coordinates of the centrums as well as those of the input points.

»m - print Mathematica output

Qhull writes a Mathematica file for 2-d and 3-d convex hulls, 2-d and 3-d halfspace intersections, and 2-d Delaunay triangulations. Qhull produces a list of objects that you can assign to a variable in Mathematica, for example: "list= << <outputfilename> ". If the object is 2-d, it can be visualized by "Show[Graphics[list]] ". For 3-d objects the command is "Show[Graphics3D[list]] ". Now the object can be manipulated by commands of the form "Show[%, <parametername> -> <newvalue>]".

For Delaunay triangulation orthogonal projection is better. This can be specified, for example, by "BoxRatios: Show[%, BoxRatios -> {1, 1, 1e-8}]". To see the meaningful side of the 3-d object used to visualize 2-d Delaunay, you need to change the viewpoint: "Show[%, ViewPoint -> {0, 0, -1}]". By specifying different viewpoints you can slowly rotate objects.

For halfspace intersections, Qhull produces the dual convex hull.

See Is Qhull available for Mathematica? for URLs.

»n - print hyperplane normals with offsets

The first line is the dimension plus one. The second line is the number of facets. The remaining lines are the normals for each facet, one normal per line. The facet's offset follows its normal coefficients.

The normals point outward, i.e., the convex hull satisfies Ax <= -b where A is the matrix of coefficients and b is the vector of offsets.

If cdd output is specified ('FD'), Qhull prints the command line, the keyword "begin", the number of facets, the dimension (plus one), the keyword "real", and the normals for each facet. The facet's negative offset precedes its normal coefficients (i.e., if the origin is an interior point, the offset is positive). Qhull ends the output with the keyword "end".

»o - print OFF file format

The output is:

  • The first line is the dimension
  • The second line is the number of points, the number of facets, and the number of ridges.
  • All of the input points follow, one per line.
  • Then Qhull prints the vertices for each facet. Each facet is on a separate line. The first number is the number of vertices. The remainder is the indices of the corresponding points. The vertices are oriented in 2-d, 3-d, and in simplicial facets.

Option 'Ft' prints the same information with added points for non-simplicial facets.

Option 'i' displays vertices without the point coordinates. Option 'p' displays the point coordinates without vertex and facet information.

In 3-d, Geomview can load the file directly if you delete the first line (e.g., by piping through 'tail +2').

For Voronoi diagrams (qvoronoi), option 'o' prints Voronoi vertices and Voronoi regions instead of input points and facets. The first vertex is the infinity vertex [-10.101, -10.101, ...]. Then, option 'o' lists the vertices in the Voronoi region for each input site. The regions appear in site ID order. In 2-d, the vertices of a Voronoi region are sorted by adjacency (non-oriented). In 3-d and higher, the Voronoi vertices are sorted by index. See the 'FN' option for listing Voronoi regions without listing Voronoi vertices.

If you are using the Qhull library, options 'v o' have the side effect of reordering the neighbors for a vertex.

»p - print vertex and point coordinates

The first line is the dimension. The second line is the number of vertices. The remaining lines are the vertices, one vertex per line. A vertex consists of its point coordinates

With the 'Gc' and 'Gi' options, option 'p' also prints coplanar and interior points respectively.

For qvoronoi, it prints the coordinates of each Voronoi vertex.

For qdelaunay, it prints the input sites as lifted to a paraboloid. For qhalf it prints the dual points. For both, option 'p' is the same as the first section of option 'o'.

Use 'Fx' to list the point ids of the extreme points (i.e., vertices).

If a subset of the facets is selected ('Pdk', 'PDk', 'Pg' options), option 'p' only prints vertices and points associated with those facets.

If cdd-output format is selected ('FD'), the first line is "begin". The second line is the number of vertices, the dimension plus one, and "real". The vertices follow with a leading "1". Output ends with "end".

»s - print summary to stderr

The default output of Qhull is a summary to stderr. Options 'FS' and 'Fs' produce the same information for programs. Note: Windows 95 and 98 treats stderr the same as stdout. Use option 'TO file' to separate stderr and stdout.

The summary lists the number of input points, the dimension, the number of vertices in the convex hull, and the number of facets in the convex hull. It lists the number of selected ("good") facets for options 'Pg', 'Pdk', qdelaunay, or qvoronoi (Delaunay triangulations only use the lower half of a convex hull). It lists the number of coplanar points. For Delaunay triangulations without 'Qc', it lists the total number of coplanar points. It lists the number of simplicial facets in the output.

The terminology depends on the output structure.

The summary lists these statistics:

  • number of points processed by Qhull
  • number of hyperplanes created
  • number of distance tests (not counting statistics, summary, and checking)
  • number of merged facets (if any)
  • number of distance tests for merging (if any)
  • CPU seconds to compute the hull
  • the maximum joggle for 'QJ'
    or, the probability of precision errors for 'QJ TRn'
  • total area and volume (if computed, see 'FS' 'FA' 'Fa' 'PAn')
  • max. distance of a point above a facet (if non-zero)
  • max. distance of a vertex below a facet (if non-zero)

The statistics include intermediate hulls. For example 'rbox d D4 | qhull' reports merged facets even though the final hull is simplicial.

Qhull starts counting CPU seconds after it has read and projected the input points. It stops counting before producing output. In the code, CPU seconds measures the execution time of function qhull() in libqhull.c. If the number of CPU seconds is clearly wrong, check qh_SECticks in user.h.

The last two figures measure the maximum distance from a point or vertex to a facet. They are not printed if less than roundoff or if not merging. They account for roundoff error in computing the distance (c.f., option 'Rn'). Use 'Fs' to report the maximum outer and inner plane.

A number may appear in parentheses after the maximum distance (e.g., 2.1x). It is the ratio between the maximum distance and the worst-case distance due to merging two simplicial facets. It should be small for 2-d, 3-d, and 4-d, and for higher dimensions with 'Qx'. It is not printed if less than 0.05.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-optp.htm b/html/qh-optp.htm index d641a08..3793854 100644 --- a/html/qh-optp.htm +++ b/html/qh-optp.htm @@ -1,249 +1,249 @@ Qhull print options (P)

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull print options (P)

This section lists the print options for Qhull. These options are indicated by 'P' followed by a letter. See Output, Geomview, and Format for other output options. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Print options

 
General
Pp
do not report precision problems
Po
force output despite precision problems
Po
if error, output neighborhood of facet
 
 
Select
Pdk:n
print facets with normal[k] >= n (default 0.0)
PDk:n
print facets with normal[k] <= n
PFn
print facets whose area is at least n
Pg
print good facets only (needs 'QGn' or 'QVn ')
PMn
print n facets with most merges
PAn
print n largest facets by area
PG
print neighbors of good facets

»PAn - keep n largest facets by area

The n largest facets are marked good for printing. This may be useful for approximating a hull. Unless 'PG' is set, 'Pg' is automatically set.

»Pdk:n - print facet if normal[k] >= n

For a given output, print only those facets with normal[k] >= n and drop the others. For example, 'Pd0:0.5' prints facets with normal[0] >= 0.5 . The default value of n is zero. For example in 3-d, 'Pd0d1d2' prints facets in the positive octant.

If no facets match, the closest facet is returned.

On Windows 95, do not combine multiple options. A 'd' is considered part of a number. For example, use 'Pd0:0.5 Pd1:0.5' instead of 'Pd0:0.5d1:0.5'.

»PDk:n - print facet if normal[k] <= n

For a given output, print only those facets with normal[k] <= n and drop the others. For example, 'PD0:0.5' prints facets with normal[0] <= 0.5 . The default value of n is zero. For example in 3-d, 'PD0D1D2' displays facets in the negative octant.

If no facets match, the closest facet is returned.

In 2-d, 'd G PD2' displays the Delaunay triangulation instead of the corresponding paraboloid.

Be careful of placing 'Dk' or 'dk' immediately after a real number. Some compilers treat the 'D' as a double precision exponent.

»PFn - keep facets whose area is at least n

The facets with area at least n are marked good for printing. This may be useful for approximating a hull. Unless 'PG' is set, 'Pg' is automatically set.

»Pg - print good facets

Qhull can mark facets as "good". This is used to

  • mark the lower convex hull for Delaunay triangulations and Voronoi diagrams
  • mark the facets that are visible from a point (the 'QGn ' option)
  • mark the facets that contain a point (the 'QVn' option).
  • indicate facets with a large enough area (options 'PAn' and 'PFn')

Option 'Pg' only prints good facets that also meet 'Pdk' and 'PDk' options. It is automatically set for options 'PAn', 'PFn ', 'QGn', and 'QVn'.

»PG - print neighbors of good facets

Option 'PG' can be used with or without option 'Pg' to print the neighbors of good facets. For example, options 'QGn' and 'QVn' print the horizon facets for point n.

»PMn - keep n facets with most merges

The n facets with the most merges are marked good for printing. This may be useful for approximating a hull. Unless 'PG' is set, 'Pg' is automatically set.

Use option 'Fm' to print merges per facet.

»Po - force output despite precision problems

Use options 'Po' and 'Q0' if you can not merge facets, triangulate the output ('Qt'), or joggle the input (QJ).

Option 'Po' can not force output when duplicate ridges or duplicate facets occur. It may produce erroneous results. For these reasons, merged facets, joggled input, or exact arithmetic are better.

If you need a simplicial Delaunay triangulation, use joggled input 'QJ' or triangulated output 'Ft'.

Option 'Po' may be used without 'Q0' to remove some steps from Qhull or to output the neighborhood of an error.

Option 'Po' may be used with option 'Q5') to skip qh_check_maxout (i.e., do not determine the maximum outside distance). This can save a significant amount of time.

If option 'Po' is used,

  • most precision errors allow Qhull to continue.
  • verify ('Tv') does not check coplanar points.
  • points are not partitioned into flipped facets and a flipped facet is always visible to a point. This may delete flipped facets from the output.

»Po - if error, output neighborhood of facet

If an error occurs before the completion of Qhull and tracing is not active, 'Po' outputs a neighborhood of the erroneous facets (if any). It uses the current output options.

See 'Po' - force output despite precision problems.

»Pp - do not report precision problems

With option 'Pp', Qhull does not print statistics about precision problems, and it removes some of the warnings. It removes the narrow hull warning.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-optq.htm b/html/qh-optq.htm index 94140c8..b778362 100644 --- a/html/qh-optq.htm +++ b/html/qh-optq.htm @@ -1,709 +1,709 @@ Qhull control options (Q)

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull control options (Q)

This section lists the control options for Qhull. These options are indicated by 'Q' followed by a letter.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Qhull control options

 
General
Qu
compute upper hull for furthest-site Delaunay triangulation
Qc
keep coplanar points with nearest facet
Qi
keep interior points with nearest facet
QJ
joggled input to avoid precision problems
Qt
triangulated output
 
 
Precision handling
Qz
add a point-at-infinity for Delaunay triangulations
Qx
exact pre-merges (allows coplanar facets)
Qs
search all points for the initial simplex
Qbb
scale last coordinate to [0,m] for Delaunay
Qv
test vertex neighbors for convexity
 
 
Transform input
Qbk:0Bk:0
drop dimension k from input
QRn
random rotation (n=seed, n=0 time, n=-1 time/no rotate)
Qbk:n
scale coord[k] to low bound of n (default -0.5)
QBk:n
scale coord[k] to upper bound of n (default 0.5)
QbB
scale input to fit the unit cube
 
 
Select facets
QVn
good facet if it includes point n, -n if not
QGn
good facet if visible from point n, -n for not visible
Qg
only build good facets (needs 'QGn', 'QVn ', or 'Pdk')
 
 
Experimental
Q4
avoid merging old facets into new facets
Q5
do not correct outer planes at end of qhull
Q3
do not merge redundant vertices
Q6
do not pre-merge concave or coplanar facets
Q0
do not pre-merge facets with 'C-0' or 'Qx'
Q8
ignore near-interior points
Q2
merge all non-convex at once instead of independent sets
Qf
partition point to furthest outside facet
Q7
process facets depth-first instead of breadth-first
Q9
process furthest of furthest points
Q10
no special processing for narrow distributions
Q11
copy normals and recompute centrums for tricoplanar facets
Qm
process points only if they would increase the max. outer plane
Qr
process random outside points instead of furthest one
Q1
sort merges by type instead of angle

»Qbb - scale the last coordinate to [0,m] for Delaunay

After scaling with option 'Qbb', the lower bound of the last coordinate will be 0 and the upper bound will be the maximum width of the other coordinates. Scaling happens after projecting the points to a paraboloid and scaling other coordinates.

Option 'Qbb' is automatically set for qdelaunay and qvoronoi. Option 'Qbb' is automatically set for joggled input 'QJ'.

Option 'Qbb' should be used for Delaunay triangulations with integer coordinates. Since the last coordinate is the sum of squares, it may be much larger than the other coordinates. For example, rbox 10000 D2 B1e8 | qhull d has precision problems while rbox 10000 D2 B1e8 | qhull d Qbb is OK.

»QbB - scale the input to fit the unit cube

After scaling with option 'QbB', the lower bound will be -0.5 and the upper bound +0.5 in all dimensions. For different bounds change qh_DEFAULTbox in user.h (0.5 is best for Geomview).

For Delaunay and Voronoi diagrams, scaling happens after projection to the paraboloid. Under precise arithmetic, scaling does not change the topology of the convex hull. Scaling may reduce precision errors if coordinate values vary widely.

»Qbk:n - scale coord[k] to low bound

After scaling, the lower bound for dimension k of the input points will be n. 'Qbk' scales coord[k] to -0.5.

»QBk:n - scale coord[k] to upper bound

After scaling, the upper bound for dimension k of the input points will be n. 'QBk' scales coord[k] to 0.5.

»Qbk:0Bk:0 - drop dimension k from the input points

Drop dimension k from the input points. For example, 'Qb1:0B1:0' deletes the y-coordinate from all input points. This allows the user to take convex hulls of sub-dimensional objects. It happens before the Delaunay and Voronoi transformation. It happens after the halfspace transformation for both the data and the feasible point.

»Qc - keep coplanar points with nearest facet

During construction of the hull, a point is coplanar if it is between 'Wn' above and 'Un' below a facet's hyperplane. A different definition is used for output from Qhull.

For output, a coplanar point is above the minimum vertex (i.e., above the inner plane). With joggle ('QJ'), a coplanar point includes points within one joggle of the inner plane.

With option 'Qc', output formats 'p ', 'f', 'Gp', 'Fc', 'FN', and 'FP' will print the coplanar points. With options 'Qc Qi' these outputs include the interior points.

For Delaunay triangulations (qdelaunay or qvoronoi), a coplanar point is a point that is nearly incident to a vertex. All input points are either vertices of the triangulation or coplanar.

Qhull stores coplanar points with a facet. While constructing the hull, it retains all points within qh_RATIOnearInside (user.h) of a facet. In qh_check_maxout(), it uses these points to determine the outer plane for each facet. With option 'Qc', qh_check_maxout() retains points above the minimum vertex for the hull. Other points are removed. If qh_RATIOnearInside is wrong or if options 'Q5 Q8' are set, a coplanar point may be missed in the output (see Qhull limitations).

»Qf - partition point to furthest outside facet

After adding a new point to the convex hull, Qhull partitions the outside points and coplanar points of the old, visible facets. Without the 'f ' option and merging, it assigns a point to the first facet that it is outside ('Wn'). When merging, it assigns a point to the first facet that is more than several times outside (see qh_DISToutside in user.h).

If option 'Qf' is selected, Qhull performs a directed search (no merging) or an exhaustive search (merging) of new facets. Option 'Qf' may reduce precision errors if pre-merging does not occur.

Option 'Q9' processes the furthest of all furthest points.

»Qg - only build good facets (needs 'QGn' 'QVn' or 'Pdk')

Qhull has several options for defining and printing good facets. With the 'Qg' option, Qhull will only build those facets that it needs to determine the good facets in the output. This may speed up Qhull in 2-d and 3-d. It is useful for furthest-site Delaunay triangulations (qdelaunay Qu, invoke with 'qhull d Qbb Qu Qg'). It is not effective in higher dimensions because many facets see a given point and contain a given vertex. It is not guaranteed to work for all combinations.

See 'QGn', 'QVn', and 'Pdk' for defining good facets, and 'Pg' and 'PG' for printing good facets and their neighbors. If pre-merging ('C-n') is not used and there are coplanar facets, then 'Qg Pg' may produce a different result than 'Pg'.

»QGn - good facet if visible from point n, -n for not visible

With option 'QGn', a facet is good (see 'Qg' and 'Pg') if it is visible from point n. If n < 0, a facet is good if it is not visible from point n. Point n is not added to the hull (unless 'TCn' or 'TPn').

With rbox, use the 'Pn,m,r' option to define your point; it will be point 0 ('QG0').

»Qi - keep interior points with nearest facet

Normally Qhull ignores points that are clearly interior to the convex hull. With option 'Qi', Qhull treats interior points the same as coplanar points. Option 'Qi' does not retain coplanar points. You will probably want 'Qc ' as well.

Option 'Qi' is automatically set for 'qdelaunay Qc' and 'qvoronoi Qc'. If you use 'qdelaunay Qi' or 'qvoronoi Qi', option 's' reports all nearly incident points while option 'Fs' reports the number of interior points (should always be zero).

With option 'Qi', output formats 'p', 'f','Gp', 'Fc', 'FN', and 'FP' include interior points.

»QJ or QJn - joggled input to avoid precision errors

Option 'QJ' or 'QJn' joggles each input coordinate by adding a random number in the range [-n,n]. If a precision error occurs, It tries again. If precision errors still occur, Qhull increases n ten-fold and tries again. The maximum value for increasing n is 0.01 times the maximum width of the input. Option 'QJ' selects a default value for n. User.h defines these parameters and a maximum number of retries. See Merged facets or joggled input.

Users of joggled input should consider converting to triangulated output ('Qt'). Triangulated output is approximately 1000 times more accurate than joggled input.

Option 'QJ' also sets 'Qbb' for Delaunay triangulations and Voronoi diagrams. It does not set 'Qbb' if 'Qbk:n' or 'QBk:n' are set.

If 'QJn' is set, Qhull does not merge facets unless requested to. All facets are simplicial (triangular in 2-d). This may be important for your application. You may also use triangulated output ('Qt') or Option 'Ft'.

Qhull adjusts the outer and inner planes for 'QJn' ('Fs'). They are increased by sqrt(d)*n to account for the maximum distance between a joggled point and the corresponding input point. Coplanar points ('Qc') require an additional sqrt(d)*n since vertices and coplanar points may be joggled in opposite directions.

For Delaunay triangulations (qdelaunay), joggle happens before lifting the input sites to a paraboloid. Instead of 'QJ', you may use triangulated output ('Qt')

This option is deprecated for Voronoi diagrams (qvoronoi). It triangulates cospherical points, leading to duplicated Voronoi vertices.

By default, 'QJn' uses a fixed random number seed. To use time as the random number seed, select 'QR-1'. The summary ('s') will show the selected seed as 'QR-n'.

With 'QJn', Qhull does not error on degenerate hyperplane computations. Except for Delaunay and Voronoi computations, Qhull does not error on coplanar points.

Use option 'FO' to display the selected options. Option 'FO' displays the joggle and the joggle seed. If Qhull restarts, it will redisplay the options.

Use option 'TRn' to estimate the probability that Qhull will fail for a given 'QJn'.

»Qm - only process points that increase the maximum outer plane

Qhull reports the maximum outer plane in its summary ('s'). With option 'Qm', Qhull does not process points that are below the current, maximum outer plane. This is equivalent to always adjusting 'Wn ' to the maximum distance of a coplanar point to a facet. It is ignored for points above the upper convex hull of a Delaunay triangulation. Option 'Qm' is no longer important for merging.

»Qr - process random outside points instead of furthest ones

Normally, Qhull processes the furthest point of a facet's outside points. Option 'Qr' instead selects a random outside point for processing. This makes Qhull equivalent to the randomized incremental algorithms.

The original randomization algorithm by Clarkson and Shor ['89] used a conflict list which is equivalent to Qhull's outside set. Later randomized algorithms retained the previously constructed facets.

To compare Qhull to the randomized algorithms with option 'Qr', compare "hyperplanes constructed" and "distance tests". Qhull does not report CPU time because the randomization is inefficient.

»QRn - random rotation

Option 'QRn' randomly rotates the input. For Delaunay triangulations (qdelaunay or qvoronoi), it rotates the lifted points about the last axis.

If n=0, use time as the random number seed. If n>0, use n as the random number seed. If n=-1, don't rotate but use time as the random number seed. If n<-1, don't rotate but use n as the random number seed.

»Qs - search all points for the initial simplex

Qhull constructs an initial simplex from d+1 points. It selects points with the maximum and minimum coordinates and non-zero determinants. If this fails, it searches all other points. In 8-d and higher, Qhull selects points with the minimum x or maximum coordinate (see qh_initialvertices in poly2.c ). It rejects points with nearly zero determinants. This should work for almost all input sets.

If Qhull can not construct an initial simplex, it reports a descriptive message. Usually, the point set is degenerate and one or more dimensions should be removed ('Qbk:0Bk:0'). If not, use option 'Qs'. It performs an exhaustive search for the best initial simplex. This is expensive is high dimensions.

»Qt - triangulated output

By default, qhull merges facets to handle precision errors. This produces non-simplicial facets (e.g., the convex hull of a cube has 6 square facets). Each facet is non-simplicial because it has four vertices.

Use option 'Qt' to triangulate all non-simplicial facets before generating results. Alternatively, use joggled input ('QJ') to prevent non-simplical facets. Unless 'Pp' is set, qhull produces a warning if 'QJ' and 'Qt' are used together.

For Delaunay triangulations (qdelaunay), triangulation occurs after lifting the input sites to a paraboloid and computing the convex hull.

Option 'Qt' is deprecated for Voronoi diagrams (qvoronoi). It triangulates cospherical points, leading to duplicated Voronoi vertices.

Option 'Qt' may produce degenerate facets with zero area.

Facet area and hull volumes may differ with and without 'Qt'. The triangulations are different and different triangles may be ignored due to precision errors.

With sufficient merging, the ridges of a non-simplicial facet may share more than two neighboring facets. If so, their triangulation ('Qt') will fail since two facets have the same vertex set.

»Qu - compute upper hull for furthest-site Delaunay triangulation

When computing a Delaunay triangulation (qdelaunay or qvoronoi), Qhull computes both the the convex hull of points on a paraboloid. It normally prints facets of the lower hull. These correspond to the Delaunay triangulation. With option 'Qu', Qhull prints facets of the upper hull. These correspond to the furthest-site Delaunay triangulation and the furthest-site Voronoi diagram.

Option 'qhull d Qbb Qu Qg' may improve the speed of option 'Qu'. If you use the Qhull library, a faster method is 1) use Qhull to compute the convex hull of the input sites; 2) take the extreme points (vertices) of the convex hull; 3) add one interior point (e.g., 'FV', the average of d extreme points); 4) run 'qhull d Qbb Qu' or 'qhull v Qbb Qu' on these points.

»Qv - test vertex neighbors for convexity

Normally, Qhull tests all facet neighbors for convexity. Non-neighboring facets which share a vertex may not satisfy the convexity constraint. This occurs when a facet undercuts the centrum of another facet. They should still be convex. Option 'Qv' extends Qhull's convexity testing to all neighboring facets of each vertex. The extra testing occurs after the hull is constructed..

»QVn - good facet if it includes point n, -n if not

With option 'QVn', a facet is good ('Qg', 'Pg') if one of its vertices is point n. If n<0, a good facet does not include point n.

If options 'PG' and 'Qg' are not set, option 'Pg' (print only good) is automatically set.

Option 'QVn' behaves oddly with options 'Fx' and 'qvoronoi Fv'.

If used with option 'Qg' (only process good facets), point n is either in the initial simplex or it is the first point added to the hull. Options 'QVn Qg' require either 'QJ' or 'Q0' (no merging).

»Qx - exact pre-merges (allows coplanar facets)

Option 'Qx' performs exact merges while building the hull. Option 'Qx' is set by default in 5-d and higher. Use option 'Q0' to not use 'Qx' by default. Unless otherwise specified, option 'Qx' sets option 'C-0'.

The "exact" merges are merging a point into a coplanar facet (defined by 'Vn ', 'Un', and 'C-n'), merging concave facets, merging duplicate ridges, and merging flipped facets. Coplanar merges and angle coplanar merges ('A-n') are not performed. Concavity testing is delayed until a merge occurs.

After the hull is built, all coplanar merges are performed (defined by 'C-n' and 'A-n'), then post-merges are performed (defined by 'Cn' and 'An'). If facet progress is logged ('TFn'), Qhull reports each phase and prints intermediate summaries and statistics ('Ts').

Without 'Qx' in 5-d and higher, options 'C-n' and 'A-n' may merge too many facets. Since redundant vertices are not removed effectively, facets become increasingly wide.

Option 'Qx' may report a wide facet. With 'Qx', coplanar facets are not merged. This can produce a "dent" in an intermediate hull. If a point is partitioned into a dent and it is below the surrounding facets but above other facets, one or more wide facets will occur. In practice, this is unlikely. To observe this effect, run Qhull with option 'Q6' which doesn't pre-merge concave facets. A concave facet makes a large dent in the intermediate hull.

Option 'Qx' may set an outer plane below one of the input points. A coplanar point may be assigned to the wrong facet because of a "dent" in an intermediate hull. After constructing the hull, Qhull double checks all outer planes with qh_check_maxout in poly2.c . If a coplanar point is assigned to the wrong facet, qh_check_maxout may reach a local maximum instead of locating all coplanar facets. This appears to be unlikely.

»Qz - add a point-at-infinity for Delaunay triangulations

Option 'Qz' adds a point above the paraboloid of lifted sites for a Delaunay triangulation. It allows the Delaunay triangulation of cospherical sites. It reduces precision errors for nearly cospherical sites.

»Q0 - no merging with C-0 and Qx

Turn off default merge options 'C-0' and 'Qx'.

With 'Q0' and without other pre-merge options, Qhull ignores precision issues while constructing the convex hull. This may lead to precision errors. If so, a descriptive warning is generated. See Precision issues.

»Q1 - sort merges by type instead of angle

Qhull sorts the coplanar facets before picking a subset of the facets to merge. It merges concave and flipped facets first. Then it merges facets that meet at a steep angle. With 'Q1', Qhull sorts merges by type (coplanar, angle coplanar, concave) instead of by angle. This may make the facets wider.

»Q2 - merge all non-convex at once instead of independent sets

With 'Q2', Qhull merges all facets at once instead of performing merges in independent sets. This may make the facets wider.

»Q3 - do not merge redundant vertices

With 'Q3', Qhull does not remove redundant vertices. In 6-d and higher, Qhull never removes redundant vertices (since vertices are highly interconnected). Option 'Q3' may be faster, but it may result in wider facets. Its effect is easiest to see in 3-d and 4-d.

»Q4 - avoid merging old facets into new facets

With 'Q4', Qhull avoids merges of an old facet into a new facet. This sometimes improves facet width and sometimes makes it worse.

»Q5 - do not correct outer planes at end of qhull

When merging facets or approximating a hull, Qhull tests coplanar points and outer planes after constructing the hull. It does this by performing a directed search (qh_findbest in geom.c). It includes points that are just inside the hull.

With options 'Q5' or 'Po', Qhull does not test outer planes. The maximum outer plane is used instead. Coplanar points ('Qc') are defined by 'Un'. An input point may be outside of the maximum outer plane (this appears to be unlikely). An interior point may be above 'Un' from a hyperplane.

Option 'Q5' may be used if outer planes are not needed. Outer planes are needed for options 's', 'G', 'Go ', 'Fs', 'Fo', 'FF', and 'f'.

»Q6 - do not pre-merge concave or coplanar facets

With 'Q6', Qhull does not pre-merge concave or coplanar facets. This demonstrates the effect of "dents" when using 'Qx'.

»Q7 - depth-first processing instead of breadth-first

With 'Q7', Qhull processes facets in depth-first order instead of breadth-first order. This may increase the locality of reference in low dimensions. If so, Qhull may be able to use virtual memory effectively.

In 5-d and higher, many facets are visible from each unprocessed point. So each iteration may access a large proportion of allocated memory. This makes virtual memory ineffectual. Once real memory is used up, Qhull will spend most of its time waiting for I/O.

Under 'Q7', Qhull runs slower and the facets may be wider.

»Q8 - ignore near-interior points

With 'Q8' and merging, Qhull does not process interior points that are near to a facet (as defined by qh_RATIOnearInside in user.h). This avoids partitioning steps. It may miss a coplanar point when adjusting outer hulls in qh_check_maxout(). The best value for qh_RATIOnearInside is not known. Options 'Q8 Qc' may be sufficient.

»Q9 - process furthest of furthest points

With 'Q9', Qhull processes the furthest point of all outside sets. This may reduce precision problems. The furthest point of all outside sets is not necessarily the furthest point from the convex hull.

»Q10 - no special processing for narrow distributions

With 'Q10', Qhull does not special-case narrow distributions. See Limitations of merged facets for more information.

»Q11 - copy normals and recompute centrums for tricoplanar facets

Option 'Qt' triangulates non-simplicial facets into "tricoplanar" facets. Normally tricoplanar facets share the same normal, centrum, and Voronoi vertex. They can not be merged or replaced. With option 'Q11', Qhull duplicates the normal and Voronoi vertex. It recomputes the centrum.

Use 'Q11' if you use the Qhull library to add points incrementally and call qh_triangulate() after each point. Otherwise, Qhull will report an error when it tries to merge and replace a tricoplanar facet.

With sufficient merging and new points, option 'Q11' may lead to precision problems such as duplicate ridges and concave facets. For example, if qh_triangulate() is added to qh_addpoint(), RBOX 1000 s W1e-12 t1001813667 P0 | QHULL d Q11 Tv, reports an error due to a duplicate ridge.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-optt.htm b/html/qh-optt.htm index 59e6f55..d0f4805 100644 --- a/html/qh-optt.htm +++ b/html/qh-optt.htm @@ -1,275 +1,275 @@ Qhull trace options (T)

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


[delaunay] Qhull trace options (T)

This section lists the trace options for Qhull. These options are indicated by 'T' followed by a letter. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Programs OptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

Trace options

 
General
Tz
output error information to stdout instead of stderr
TI file
input data from a file
TO file
output results to a file
Ts
print statistics
TFn
report progress whenever n or more facets created
TRn
rerun qhull n times
Tv
verify result: structure, convexity, and point inclusion
 
 
Debugging
Tc
check frequently during execution
TVn
stop qhull after adding point n
TCn
stop qhull after building cone for point n
TV-n
stop qhull before adding point n
T4
trace at level n, 4=all, 5=mem/gauss, -1= events
TWn
trace merge facets when width > n
TMn
turn on tracing at merge n
TPn
turn on tracing when point n added to hull

»Tc - check frequently during execution

Qhull includes frequent checks of its data structures. Option 'Tc' will catch most inconsistency errors. It is slow and should not be used for production runs. Option 'Tv' performs the same checks after the hull is constructed.

»TCn - stop qhull after building cone for point n

Qhull builds a cone from the point to its horizon facets. Option 'TCn' stops Qhull just after building the cone. The output for 'f' includes the cone and the old hull.'.

»TFn - report summary whenever n or more facets created

Option 'TFn' reports progress whenever more than n facets are created. The test occurs just before adding a new point to the hull. During post-merging, 'TFn' reports progress after more than n/2 merges.

»TI file - input data from file

Input data from 'file' instead of stdin. The filename may not contain spaces or use single quotes. You may use I/O redirection instead (e.g., 'rbox 10 | qdelaunay >results').

»TMn - turn on tracing at merge n

Turn on tracing at n'th merge.

»Tn - trace at level n

Qhull includes full execution tracing. 'T-1' traces events. 'T1' traces the overall execution of the program. 'T2' and 'T3' trace overall execution and geometric and topological events. 'T4' traces the algorithm. 'T5' includes information about memory allocation and Gaussian elimination. 'T1' is useful for logging progress of Qhull in high dimensions.

Option 'Tn' can produce large amounts of output. Use options 'TPn', 'TWn', and 'TMn' to selectively turn on tracing. Since all errors report the last processed point, option 'TPn' is particularly useful.

Different executions of the same program may produce different traces and different results. The reason is that Qhull uses hashing to match ridges of non-simplicial facets. For performance reasons, the hash computation uses memory addresses which may change across executions.

»TO file - output results to file

Redirect stdout to 'file'. The filename may be enclosed in single quotes. Unix and Windows NT users may use I/O redirection instead (e.g., 'rbox 10 | qdelaunay >results').

Windows95 users should always use 'TO file'. If they use I/O redirection, error output is not sent to the console. Qhull uses single quotes instead of double quotes because a missing double quote can freeze Windows95 (e.g., do not run, rbox 10 | qhull TO "x)

»TPn - turn on tracing when point n added to hull

Option 'TPn' turns on tracing when point n is added to the hull. It also traces partitions of point n. This option reduces the output size when tracing. It is the normal method to determine the cause of a Qhull error. All Qhull errors report the last point added.

Use options 'TPn TVn' to trace the addition of point n to the convex hull and stop when done.

If used with option 'TWn', 'TPn' turns off tracing after adding point n to the hull. Use options 'TPn TWn' to trace the addition of point n to the convex hull, partitions of point n, and wide merges.

»TRn - rerun qhull n times

Option 'TRn' reruns Qhull n times. It is usually used with 'QJn' to determine the probability that a given joggle will fail. The summary ('s') lists the failure rate and the precision errors that occurred. Option 'Ts' will report statistics for all of the runs. Trace and output options only apply to the last run. An event trace, 'T-1' reports events for all runs.

Tracing applies to the last run of Qhull. If an error is reported, the options list the run number as "_run". To trace this run, set 'TRn' to the same value.

»Ts - print statistics

Option 'Ts' collects statistics and prints them to stderr. For Delaunay triangulations, the angle statistics are restricted to the lower or upper envelope.

»Tv - verify result: structure, convexity, and point inclusion

Option 'Tv' checks the topological structure, convexity, and point inclusion. If precision problems occurred, facet convexity is tested whether or not 'Tv' is selected. Option 'Tv' does not check point inclusion if forcing output with 'Po', or if 'Q5' is set.

The convex hull of a set of points is the smallest polytope that includes the points. Option 'Tv' tests point inclusion. Qhull verifies that all points are below all outer planes (facet->maxoutside). Point inclusion is exhaustive if merging or if the facet-point product is small enough; otherwise Qhull verifies each point with a directed search (qh_findbest). To force an exhaustive test when using option 'C-0' (default), use 'C-1e-30' instead.

Point inclusion testing occurs after producing output. It prints a message to stderr unless option 'Pp' is used. This allows the user to interrupt Qhull without changing the output.

With 'qvoronoi Fi' and 'qvoronoi Fo', option 'Tv' collects statistics that verify all Voronoi vertices lie on the separating hyperplane, and for bounded regions, all separating hyperplanes are perpendicular bisectors.

»TV-n - stop qhull before adding point n

Qhull adds one point at a time to the convex hull. See how Qhull adds a point. Option 'TV-n' stops Qhull just before adding a new point. Output shows the hull at this time.

»TVn - stop qhull after adding point n

Option 'TVn' stops Qhull after it has added point n. Output shows the hull at this time.

»TWn - trace merge facets when width > n

Along with TMn, this option allows the user to determine the cause of a wide merge.

»Tz - send all output to stdout

Redirect stderr to stdout.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qh-quick.htm b/html/qh-quick.htm index 20ed002..ebc2863 100644 --- a/html/qh-quick.htm +++ b/html/qh-quick.htm @@ -1,491 +1,491 @@ Qhull quick reference

Up: Home page for Qhull
Up: Qhull manual
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull internals
To: Qhull functions, macros, and data structures
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


[cone] Qhull quick reference

This section lists all programs and options in Qhull. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber

 


Qhull programs

» ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

qconvex -- convex hull
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qdelaunay -- Delaunay triangulation
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qdelaunay Qu -- furthest-site Delaunay triangulation
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qhalf -- halfspace intersection about a point
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qvoronoi -- Voronoi diagram
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
qvoronoi Qu -- furthest-site Voronoi diagram
synopsis • input • outputs • controls • graphics • notes • conventions • options
 
rbox -- generate point distributions for qhull
synopsis • outputs • examples • notes • options
 
qhull -- convex hull and related structures
synopsis • input • outputs • controls • options
 
Qhull options

» ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace

'Fa' Farea 'FA' FArea-total 'Fc' Fcoplanars 'FC' FCentrums
'Fd' Fd-cdd-in 'FD' FD-cdd-out 'FF' FF-dump-xridge 'Fi' Finner
'Fi' Finner_bounded 'FI' FIDs 'Fm' Fmerges 'FM' FMaple
'Fn' Fneighbors 'FN' FNeigh-vertex 'Fo' Fouter 'Fo' Fouter_unbounded
'FO' FOptions 'Fp' Fpoint-intersect 'FP' FPoint_near 'FQ' FQhull
'Fs' Fsummary 'FS' FSize 'Ft' Ftriangles 'Fv' Fvertices
'Fv' Fvoronoi 'FV' FVertex-ave 'Fx' Fxtremes Merged facets or joggled input
 
'PAn' PArea-keep 'Pdk:n' Pdrop_low 'PDk:n' Pdrop_high 'Pg' Pgood
'PFn' PFacet_area_keep 'PG' PGood_neighbors 'PMn' PMerge-keep 'Po' Poutput_forced
'Po' Poutput_error 'Pp' Pprecision_not
 
'd' delaunay 'v' voronoi 'G' Geomview 'H' Halfspace
'f' facet_dump 'i' incidences 'm' mathematica 'n' normals
'o' OFF_format 'p' points 's' summary
 
'Gv' Gvertices 'Gp' Gpoints 'Ga' Gall_points 'Gn' Gno_planes
'Gi' Ginner 'Gc' Gcentrums 'Gh' Ghyperplanes 'Gr' Gridges
'Go' Gouter 'GDn' GDrop_dim 'Gt' Gtransparent
 
'T4' T4_trace 'Tc' Tcheck_often 'Ts' Tstatistics 'Tv' Tverify
'Tz' Tz_stdout 'TFn' TFacet_log 'TI file' TInput_file 'TPn' TPoint_trace
'TMn' TMerge_trace 'TO file' TOutput_file 'TRn' TRerun 'TWn' TWide_trace
'TV-n' TVertex_stop_before
'TVn' TVertex_stop_after 'TCn' TCone_stop_after
 
'A-n' Angle_max_pre 'An' Angle_max_post 'C-0' Centrum_roundoff 'C-n' Centrum_size_pre
'Cn' Centrum_size_post 'En' Error_round 'Rn' Random_dist 'Vn' Visible_min
'Un' Ucoplanar_max 'Wn' Wide_outside
 
'Qbk:n' Qbound_low 'QBk:n' QBound_high 'Qbk:0Bk:0' Qbound_drop 'QbB' QbB-scale-box
'Qbb' Qbb-scale-last 'Qc' Qcoplanar 'Qf' Qfurthest 'Qg' Qgood_only
'QGn' QGood_point 'Qi' Qinterior 'Qm' Qmax_out 'QJn' QJoggle
'Qr' Qrandom 'QRn' QRotate 'Qs' Qsearch_1st 'Qt' Qtriangulate
'Qu' QupperDelaunay 'QVn' QVertex_good 'Qv' Qvneighbors 'Qx' Qxact_merge
'Qz' Qzinfinite
 
'Q0' Q0_no_premerge 'Q1' Q1_no_angle 'Q2' Q2_no_independ 'Q3' Q3_no_redundant
'Q4' Q4_no_old 'Q5' Q5_no_check_out 'Q6' Q6_no_concave 'Q7' Q7_depth_first
'Q8' Q8_no_near_in 'Q9' Q9_pick_furthest 'Q10' Q10_no_narrow 'Q11' Q11_trinormals


Up: Home page for Qhull
Up: Qhull manual
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: Qhull internals
To: Qhull functions, macros, and data structures
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qhalf.htm b/html/qhalf.htm index ef8b15f..18da79e 100644 --- a/html/qhalf.htm +++ b/html/qhalf.htm @@ -1,598 +1,598 @@ qhalf -- halfspace intersection about a point

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


[halfspace]qhalf -- halfspace intersection about a point

The intersection of a set of halfspaces is a polytope. The polytope may be unbounded. See Preparata & Shamos ['85] for a discussion. In low dimensions, halfspace intersection may be used for linear programming.

Example: rbox c | qconvex FQ FV n | qhalf Fp
Print the intersection of the facets of a cube. rbox c generates the vertices of a cube. qconvex FV n returns of average of the cube's vertices (in this case, the origin) and the halfspaces that define the cube. qhalf Fp computes the intersection of the halfspaces about the origin. The intersection is the vertices of the original cube.

Example: rbox c d G0.55 | qconvex FQ FV n | qhalf Fp

Print the intersection of the facets of a cube and a diamond. There are 24 facets and 14 intersection points. Four facets define each diamond vertex. Six facets define each cube vertex.

Example: rbox c d G0.55 | qconvex FQ FV n | qhalf Fp Qt

Same as above except triangulate before computing the intersection points. Three facets define each intersection point. There are two duplicates of the diamond and four duplicates of the cube.

Qhull computes a halfspace intersection by the geometric duality between points and halfspaces. See halfspace examples, qhalf notes, and option 'p' of qhalf outputs.

By default, halfspace intersections may be defined by more than d halfspaces. See the previous cube and diamond example. This is the expected output for halfspace intersection.

You can try triangulated output and joggled input. It demonstrates that triangulated output is more accurate than joggled input.

If you use 'Qt' (triangulated output), all halfspace intersections are simplicial (e.g., three halfspaces per intersection in 3-d). In 3-d, if more than three halfspaces intersect at the same point, triangulated output will produce duplicate intersections, one for each additional halfspace. See the previous cube and diamond example.

If you use 'QJ' (joggled input), all halfspace intersections are simplicial. This may lead to nearly identical intersections. For example, replace 'Qt' with 'QJ' above and compare the duplicated intersections. See Merged facets or joggled input.

The 'qhalf' program is equivalent to 'qhull H' in 2-d to 4-d, and 'qhull H Qx' in 5-d and higher. It disables the following Qhull options: d n v Qbb QbB Qf Qg Qm Qr QR Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0,etc. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»qhalf synopsis

 qhalf- halfspace intersection about a point.
     input (stdin): [dim, 1, interior point]
                    dim+1, n
                    halfspace coefficients + offset
     comments start with a non-numeric character
 
 options (qhalf.htm):
     Hn,n - specify coordinates of interior point
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Tv   - verify result: structure, convexity, and redundancy
     .    - concise list of all options
     -    - one-line description of all options
 
 output options (subset):
     s    - summary of results (default)
     Fp   - intersection coordinates
     Fv   - non-redundant halfspaces incident to each intersection
     Fx   - non-redundant halfspaces
     o    - OFF file format (dual convex hull)
     G    - Geomview output (dual convex hull)
     m    - Mathematica output (dual convex hull)
     QVn  - print intersections for halfspace n, -n if not
     TO file - output results to file, may be enclosed in single quotes
 
 examples:
     rbox d | qconvex n | qhalf s H0,0,0 Fp
     rbox c | qconvex FV n | qhalf s i
     rbox c | qconvex FV n | qhalf s o
 

»qhalf input

The input data on stdin consists of:

  • [optional] interior point
    • dimension
    • 1
    • coordinates of interior point
  • dimension + 1
  • number of halfspaces
  • halfspace coefficients followed by offset

Use I/O redirection (e.g., qhalf < data.txt), a pipe (e.g., rbox c | qconvex FV n | qhalf), or the 'TI' option (e.g., qhalf TI data.txt).

Qhull needs an interior point to compute the halfspace intersection. An interior point is clearly inside all of the halfspaces. The interior point may be in the input. If not, option 'Hn,n' defines the interior point as [n,n,0,...] where 0 is the default coordinate (e.g., 'H0' is the origin). Use linear programming if you do not know the interior point (see halfspace notes),

The input to qhalf is a set of halfspaces. Each halfspace is defined by d coefficients followed by a signed offset. This defines a linear inequality. The coefficients define a vector that is normal to the halfspace. The vector may have any length. If it has length one, the offset is the distance from the origin to the halfspace's boundary. The distance from the interior point to each halfspace is negative.

The halfspace format is the same as Qhull's output options 'n', 'Fo', and 'Fi'. Use option 'Fd' to use cdd format for the halfspaces.

For example, here is the input for computing the intersection of halfplanes that form a cube.

rbox c | qconvex FQ FV n TO data

 RBOX c | QCONVEX FQ FV n
 3 1
      0      0      0
 4
 6
      0      0     -1   -0.5
      0     -1      0   -0.5
      1      0      0   -0.5
     -1      0      0   -0.5
      0      1      0   -0.5
      0      0      1   -0.5
 

qhalf s Fp < data

 
 Halfspace intersection by the convex hull of 6 points in 3-d:
 
   Number of halfspaces: 6
   Number of non-redundant halfspaces: 6
   Number of intersection points: 8
 
 Statistics for: RBOX c | QCONVEX FQ FV n | QHALF s Fp
 
   Number of points processed: 6
   Number of hyperplanes created: 11
   Number of distance tests for qhull: 11
   Number of merged facets: 1
   Number of distance tests for merging: 45
   CPU seconds to compute hull (after input):  0
 
 3
 3
 8
   -0.5    0.5    0.5
    0.5    0.5    0.5
   -0.5    0.5   -0.5
    0.5    0.5   -0.5
    0.5   -0.5    0.5
   -0.5   -0.5    0.5
   -0.5   -0.5   -0.5
    0.5   -0.5   -0.5
 

»qhalf outputs

The following options control the output for halfspace intersection.

 
Intersections
FN
list intersection points for each non-redundant halfspace. The first line is the number of non-redundant halfspaces. Each remaining lines starts with the number of intersection points. For the cube example, each halfspace has four intersection points.
Fn
list neighboring intersections for each intersection point. The first line is the number of intersection points. Each remaining line starts with the number of neighboring intersections. For the cube example, each intersection point has three neighboring intersections. In 3-d, a non-simplicial intersection has more than three neighboring intersections. Use option 'QJ' to avoid non-simplicial intersections.
Fp
print intersection coordinates. The first line is the dimension and the second line is the number of intersection points. The following lines are the coordinates of each intersection.
FI
list intersection IDs. The first line is the number of intersections. The IDs follow, one per line.
 
 
Halfspaces
Fx
list non-redundant halfspaces. The first line is the number of non-redundant halfspaces. The other lines list one halfspace per line. A halfspace is non-redundant if it defines a facet of the intersection. Redundant halfspaces are ignored. For the cube example, all of the halfspaces are non-redundant.
Fv
list non-redundant halfspaces incident to each intersection point. The first line is the number of non-redundant halfspaces. Each remaining line starts with the number of non-redundant halfspaces. For the cube example, each intersection is incident to three halfspaces.
i
list non-redundant halfspaces incident to each intersection point. The first line is the number of intersection points. Each remaining line lists the incident, non-redundant halfspaces. For the cube example, each intersection is incident to three halfspaces.
Fc
list coplanar halfspaces for each intersection point. The first line is the number of intersection points. Each remaining line starts with the number of coplanar halfspaces. A coplanar halfspace is listed for one intersection point even though it is coplanar to multiple intersection points.
Qi Fc
list redundant halfspaces for each intersection point. The first line is the number of intersection points. Each remaining line starts with the number of redundant halfspaces. Use options 'Qc Qi Fc' to list coplanar and redundant halfspaces.
 
 
General
s
print summary for the halfspace intersection. Use 'Fs' if you need numeric data.
o
print vertices and facets of the dual convex hull. The first line is the dimension. The second line is the number of vertices, facets, and ridges. The vertex coordinates are next, followed by the facets, one per line.
p
print vertex coordinates of the dual convex hull. Each vertex corresponds to a non-redundant halfspace. Its coordinates are the negative of the hyperplane's coefficients divided by the offset plus the inner product of the coefficients and the interior point (-c/(b+a.p). Options 'p Qc' includes coplanar halfspaces. Options 'p Qi' includes redundant halfspaces.
m
Mathematica output for the dual convex hull in 2-d or 3-d.
FM
Maple output for the dual convex hull in 2-d or 3-d.
G
Geomview output for the dual convex hull in 2-d, 3-d, or 4-d.

»qhalf controls

These options provide additional control:

Qt
triangulated output. If a 3-d intersection is defined by more than three hyperplanes, Qhull produces duplicate intersections -- one for each extra hyperplane.
QJ
joggle the input instead of merging facets. In 3-d, this guarantees that each intersection is defined by three hyperplanes.
f
facet dump. Print the data structure for each intersection (i.e., facet)
TFn
report summary after constructing n intersections
QVn
select intersection points for halfspace n (marked 'good')
QGn
select intersection points that are visible to halfspace n (marked 'good'). Use -n for the remainder.
Qbk:0Bk:0
remove the k-th coordinate from the input. This computes the halfspace intersection in one lower dimension.
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
Qs
search all points for the initial simplex. If Qhull can not construct an initial simplex, it reports a descriptive message. Usually, the point set is degenerate and one or more dimensions should be removed ('Qbk:0Bk:0'). If not, use option 'Qs'. It performs an exhaustive search for the best initial simplex. This is expensive is high dimensions.

»qhalf graphics

To view the results with Geomview, compute the convex hull of the intersection points ('qhull FQ H0 Fp | qhull G'). See Halfspace examples.

»qhalf notes

See halfspace intersection for precision issues related to qhalf.

If you do not know an interior point for the halfspaces, use linear programming to find one. Assume, n halfspaces defined by: aj*x1+bj*x2+cj*x3+dj>=0, j=1..n. Perform the following linear program:

max(x5) aj*x1+bj*x2+cj*x3+dj*x4-x5>=0, j=1..n

Then, if [x1,x2,x3,x4,x5] is an optimal solution with x4,x5>0 we get:

aj*(x1/x4)+bj*(x2/x4)+cj*(x3/x4)+dj>=(x5/x4)>0, j=1..n

and conclude that the point [x1/x4,x2/x4,x3/x4] is in the interior of all the halfspaces. Note that x5 is optimal, so this point is "way in" the interior (good for precision errors).

After finding an interior point, the rest of the intersection algorithm is from Preparata & Shamos ['85, p. 316, "A simple case ..."]. Translate the halfspaces so that the interior point is the origin. Calculate the dual polytope. The dual polytope is the convex hull of the vertices dual to the original faces in regard to the unit sphere (i.e., halfspaces at distance d from the origin are dual to vertices at distance 1/d). Then calculate the resulting polytope, which is the dual of the dual polytope, and translate the origin back to the interior point [S. Spitz and S. Teller].

»qhalf conventions

The following terminology is used for halfspace intersection in Qhull. This is the hardest structure to understand. The underlying structure is a convex hull with one vertex per non-redundant halfspace. See convex hull conventions and Qhull's data structures.

  • interior point - a point in the intersection of the halfspaces. Qhull needs an interior point to compute the intersection. See halfspace input.
  • halfspace - d coordinates for the normal and a signed offset. The distance to an interior point is negative.
  • non-redundant halfspace - a halfspace that defines an output facet
  • vertex - a dual vertex in the convex hull corresponding to a non-redundant halfspace
  • coplanar point - the dual point corresponding to a similar halfspace
  • interior point - the dual point corresponding to a redundant halfspace
  • intersection point- the intersection of d or more non-redundant halfspaces
  • facet - a dual facet in the convex hull corresponding to an intersection point
  • non-simplicial facet - more than d halfspaces intersect at a point
  • good facet - an intersection point that satisfies restriction 'QVn', etc.

»qhalf options

 qhalf- compute the intersection of halfspaces about a point
     http://www.qhull.org
 
 input (stdin):
     optional interior point: dimension, 1, coordinates
     first lines: dimension+1 and number of halfspaces
     other lines: halfspace coefficients followed by offset
     comments:    start with a non-numeric character
 
 options:
     Hn,n - specify coordinates of interior point
     Qt   - triangulated ouput
     QJ   - joggle input instead of merging facets
     Qc   - keep coplanar halfspaces
     Qi   - keep other redundant halfspaces
 
 Qhull control options:
     QJn  - randomly joggle input in range [-n,n]
     Qbk:0Bk:0 - remove k-th coordinate from input
     Qs   - search all halfspaces for the initial simplex
     QGn  - print intersection if redundant to halfspace n, -n for not
     QVn  - print intersections for halfspace n, -n if not
 
 Trace options:
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
     Tc   - check frequently during execution
     Ts   - print statistics
     Tv   - verify result: structure, convexity, and redundancy
     Tz   - send all output to stdout
     TFn  - report summary when n or more facets created
     TI file - input data from file, no spaces or single quotes
     TO file - output results to file, may be enclosed in single quotes
     TPn  - turn on tracing when halfspace n added to intersection
     TMn  - turn on tracing at merge n
     TWn  - trace merge facets when width > n
     TVn  - stop qhull after adding halfspace n, -n for before (see TCn)
     TCn  - stop qhull after building cone for halfspace n (see TVn)
 
 Precision options:
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
     Rn   - randomly perturb computations by a factor of [1-n,1+n]
     Un   - max distance below plane for a new, coplanar halfspace
     Wn   - min facet width for outside halfspace (before roundoff)
 
 Output formats (may be combined; if none, produces a summary to stdout):
     f    - facet dump
     G    - Geomview output (dual convex hull)
     i    - non-redundant halfspaces incident to each intersection
     m    - Mathematica output (dual convex hull)
     o    - OFF format (dual convex hull: dimension, points, and facets)
     p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')
     s    - summary (stderr)
 
 More formats:
     Fc   - count plus redundant halfspaces for each intersection
          -   Qc (default) for coplanar and Qi for other redundant
     Fd   - use cdd format for input (homogeneous with offset first)
     FF   - facet dump without ridges
     FI   - ID of each intersection
     Fm   - merge count for each intersection (511 max)
     FM   - Maple output (dual convex hull)
     Fn   - count plus neighboring intersections for each intersection
     FN   - count plus intersections for each non-redundant halfspace
     FO   - options and precision constants
     Fp   - dim, count, and intersection coordinates
     FP   - nearest halfspace and distance for each redundant halfspace
     FQ   - command used for qhalf
     Fs   - summary: #int (8), dim, #halfspaces, #non-redundant, #intersections
                       for output: #non-redundant, #intersections, #coplanar
                                   halfspaces, #non-simplicial intersections
                     #real (2), max outer plane, min vertex
     Fv   - count plus non-redundant halfspaces for each intersection
     Fx   - non-redundant halfspaces
 
 Geomview output (2-d, 3-d and 4-d; dual convex hull)
     Ga   - all points (i.e., transformed halfspaces) as dots
      Gp  -  coplanar points and vertices as radii
      Gv  -  vertices (i.e., non-redundant halfspaces) as spheres
     Gi   - inner planes (i.e., halfspace intersections) only
      Gn  -  no planes
      Go  -  outer planes only
     Gc   - centrums
     Gh   - hyperplane intersections
     Gr   - ridges
     GDn  - drop dimension n in 3-d and 4-d output
 
 Print options:
     PAn  - keep n largest facets (i.e., intersections) by area
     Pdk:n- drop facet if normal[k] <= n (default 0.0)
     PDk:n- drop facet if normal[k] >= n
     Pg   - print good facets (needs 'QGn' or 'QVn')
     PFn  - keep facets whose area is at least n
     PG   - print neighbors of good facets
     PMn  - keep n facets with most merges
     Po   - force output.  If error, output neighborhood of facet
     Pp   - do not report precision problems
 
     .    - list of all options
     -    - one line descriptions of all options
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qhull-cpp.xml b/html/qhull-cpp.xml index ceb3a39..bf8f4d7 100644 --- a/html/qhull-cpp.xml +++ b/html/qhull-cpp.xml @@ -1,213 +1,213 @@ + fileid="$Id: //main/2011/qhull/html/qhull-cpp.xml#4 $$Change: 1810 $" + fileChange="$DateTime: 2015/01/17 18:28:15 $$Author: bbarber $">

Qhull C++ -- C++ interface to Qhull

- Copyright (c) 2009-2012, C.B. Barber + Copyright (c) 2009-2015, C.B. Barber

This document records Please send comments and suggestions to bradb@shore.net

Help
.
Qhull's collection APIs are modeled on Qt's collection API (QList, QVector, QHash). They support STL and Qt programming. Some of Qhull's collection classes derive from STL classes. If so, please avoid additional STL functions and operators added by inheritance. These collection classes may be rewritten to derive from Qt classes instead. See . Qhull's collection API (where applicable). For documentation, see Qt's QList, QMap, QListIterator, QMapIterator, QMutableListIterator, and QMutableMapIterator
  • STL types [list, qlinkedlist, qlist, qvector, vector] -- const_iterator, iterator
  • STL types describing iterators [list, qlinkedlist, qlist, qvector, vector] -- const_pointer, const_reference, difference_type, pointer, reference, size_type, value_type. Pointer and reference types not defined if unavailable (not needed for <algorithm>)
  • const_iterator, iterator types -- difference_type, iterator_category, pointer, reference, value_type
  • Qt types [qlinkedlist, qlist, qvector] -- ConstIterator, Iterator, QhullclassIterator, MutableQhullclassIterator. Qt's foreach requires const_iterator.
  • Types for sets/maps [hash_map, QHash] -- key_compare, key_type, mapped_type
  • Constructor -- default constructor, copy constructor, assignment operator, destructor
  • Conversion -- to/from/as corresponding C, STL, and Qt constructs. Include toQList and toStdVector (may be filtered, e.g., QhullFacetSet). Do not define fromStdList and fromQList if container is not reference counted (i.e., acts like a value)
  • Get/set -- configuration options for class
  • STL-style iterator - begin, constBegin, constEnd, end, key, value, =, *, [], ->, ++, --, +, -, ==, !=, <, <=, >, >=, const_iterator(iterator), iterator COMPARE const_iterator. An iterator is an abstraction of a pointer. It is not aware of its container.
  • Java-style iterator [qiterator.h] - countRemaining, findNext, findPrevious, hasNext, hasPrevious, next, peekNext, peekPrevious, previous, toBack, toFront, = Coordinates
  • Mutable Java-style iterator adds - insert, remove, setValue, value
  • Element access -- back, first, front, last
  • Element access w/ index -- [], at (const& only), constData, data, mid, value
  • Read-only - (int)count, empty, isEmpty, (size_t)size. Count() and size() may be filtered. If so, they may be zero when !empty().
  • Read-only for sets/maps - capacity, key, keys, reserve, resize, values
  • Operator - ==, !=, +, +=, <<
  • Read-write -- append, clear, erase, insert, move, prepend, pop_back, pop_front, push_back, push_front, removeAll, removeAt, removeFirst, removeLast, replace, swap, takeAt, takeFirst, takeLast
  • Read-write for sets/maps -- insertMulti, squeeze, take, unite
  • Search -- contains(const T &), count(const T &), indexOf, lastIndexOf
  • Search for sets/maps -- constFind, lowerBound, upperBound
  • Stream I/O -- stream <<
STL list and vector -- For unfiltered access to each element.
  • Apache: Creating your own containers -- requirements for STL containers. Iterators should define the types from 'iterator_traits'.
  • STL types -- allocator_type, const_iterator, const_pointer, const_reference, const_reverse_iterator, difference_type, iterator, iterator_category, pointer, reference, reverse_iterator, size_type, value_type
  • STL constructors -- MyType(), MyType(count), MyType(count, value), MyType(first, last), MyType(MyType&),
  • STL getter/setters -- at (random_access only), back, begin, capacity, end, front, rbegin, rend, size, max_size
  • STL predicates -- empty
  • STL iterator types -- const_pointer, const_reference, difference_type, iterator_category, pointer, reference, value_type
  • STL iterator operators -- *, -<, ++, --, +=, -=, +, -, [], ==, !=, <, >, >=, <=
  • STL operators -- =, [] (random_access only), ==, !=, <, >, <=, >=
  • STL modifiers -- assign, clear, erase, insert, pop_back, push_back, reserve, resize, swap
Qt Qlist -- For unfiltered access to each element
  • Additional Qt types -- ConstIterator, Iterator, QListIterator, QMutableListIterator
  • Additional Qt get/set -- constBegin, constEnd, count, first, last, value (random_access only)
  • Additional Qt predicates -- isEmpty
  • Additional Qt -- mid (random_access only)
  • Additional Qt search -- contains, count(T&), indexOf (random_access only), lastIndeOf (random_access only)
  • Additional Qt modifiers -- append, insert(index,value) (random_access only), move (random_access only), pop_front, prepend, push_front, removeAll, removeAt (random_access only), removeFirst, removeLast, replace, swap by index, takeAt, takeFirst, takeLast
  • Additional Qt operators -- +, <<, +=, stream << and >>
  • Unsupported types by Qt -- allocator_type, const_reverse_iterator, reverse_iterator
  • Unsupported accessors by Qt -- max_size, rbegin, rend
  • Unsupported constructors by Qt -- multi-value constructors
  • unsupported modifiers by Qt -- assign, muli-value inserts, STL's swaps
STL map and Qt QMap. These use nearly the same API as list and vector classes. They add the following.
  • STL types -- key_compare, key_type, mapped_type
  • STL search -- equal_range, find, lower_bound, upper_bound
  • Qt removes -- equal_range, key_compare
  • Qt renames -- lowerBound, upperBound
  • Qt adds -- constFind, insertMulti, key, keys, take, uniqueKeys, unite, values
  • Not applicable to map and QMap -- at, back, pop_back, pop_front, push_back, push_front, swap
  • Not applicable to QMap -- append, first, last, lastIndexOf, mid, move, prepend, removeAll, removeAt, removeFirst, removeLast, replace, squeeze, takeAt, takeFirst, takeLast
  • Not applicable to map -- assign
Qt QHash. STL extensions provide similar classes, e.g., Microsoft's stdext::hash_set. THey are nearly the same as QMap
  • Not applicable to Qhash -- lowerBound, unite, upperBound,
  • Qt adds -- squeeze
  • check... -- Throw error on failure
  • try... -- Return false on failure. Do not throw errors.
  • ...Temporarily -- lifetime depends on source. e.g., toByteArrayTemporarily
  • ...p -- indicates pointer-to.
  • end... -- points to one beyond the last available
  • private functions -- No syntactic indication. They may become public later on.
  • Error messages -- Preceed error messages with the name of the class throwing the error (e.g. "ClassName: ..."). If this is an internal error, use "ClassName inconsistent: ..."
  • parameter order -- qhRunId, dimension, coordinates, count.
  • toClass -- Convert into a Class object (makes a deep copy)
  • qRunId -- Requires Qh installed. Some routines allow 0 for limited info (e.g., operator<<)
  • Disable methods in derived classes -- If the default constructor, copy constructor, or copy assignment is disabled, it should be also disabled in derived classes (better error messages).
  • Constructor order -- default constructor, other constructors, copy constructor, copy assignment, destructor
diff --git a/html/qhull.htm b/html/qhull.htm index 7b5bf0e..ef6ad02 100644 --- a/html/qhull.htm +++ b/html/qhull.htm @@ -1,469 +1,469 @@ qhull -- convex hull and related structures

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • options


[cone]qhull -- convex hull and related structures

The convex hull of a set of points is the smallest convex set containing the points. The Delaunay triangulation and furthest-site Delaunay triangulation are equivalent to a convex hull in one higher dimension. Halfspace intersection about a point is equivalent to a convex hull by polar duality.

The qhull program provides options to build these structures and to experiment with the process. Use the qconvex, qdelaunay, qhalf, and qvoronoi programs to build specific structures. You may use qhull instead. It takes the same options and uses the same code.

Example: rbox 1000 D3 | qhull C-1e-4 FO Ts
Compute the 3-d convex hull of 1000 random points. Centrums must be 10^-4 below neighboring hyperplanes. Print the options and precision constants. When done, print statistics. These options may be used with any of the Qhull programs.
 
Example: rbox 1000 D3 | qhull d Qbb R1e-4 Q0
Compute the 3-d Delaunay triangulation of 1000 random points. Randomly perturb all calculations by [0.9999,1.0001]. Do not correct precision problems. This leads to serious precision errors.

Use the following equivalences when calling qhull in 2-d to 4-d (a 3-d Delaunay triangulation is a 4-d convex hull):

Use the following equivalences when calling qhull in 5-d and higher (a 4-d Delaunay triangulation is a 5-d convex hull):

By default, Qhull merges coplanar facets. For example, the convex hull of a cube's vertices has six facets.

If you use 'Qt' (triangulated output), all facets will be simplicial (e.g., triangles in 2-d). For the cube example, it will have 12 facets. Some facets may be degenerate and have zero area.

If you use 'QJ' (joggled input), all facets will be simplicial. The corresponding vertices will be slightly perturbed. Joggled input is less accurate that triangulated output.See Merged facets or joggled input.

The output for 4-d convex hulls may be confusing if the convex hull contains non-simplicial facets (e.g., a hypercube). See Why are there extra points in a 4-d or higher convex hull?

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»qhull synopsis

 qhull- compute convex hulls and related structures.
     input (stdin): dimension, n, point coordinates
     comments start with a non-numeric character
     halfspace: use dim+1 and put offsets after coefficients
 
 options (qh-quick.htm):
     d    - Delaunay triangulation by lifting points to a paraboloid
     d Qu - furthest-site Delaunay triangulation (upper convex hull)
     v    - Voronoi diagram as the dual of the Delaunay triangulation
     v Qu - furthest-site Voronoi diagram
     H1,1 - Halfspace intersection about [1,1,0,...] via polar duality
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Tv   - verify result: structure, convexity, and point inclusion
     .    - concise list of all options
     -    - one-line description of all options
 
 Output options (subset):
     s    - summary of results (default)
     i    - vertices incident to each facet
     n    - normals with offsets
     p    - vertex coordinates (if 'Qc', includes coplanar points)
            if 'v', Voronoi vertices
     Fp   - halfspace intersections
     Fx   - extreme points (convex hull vertices)
     FA   - compute total area and volume
     o    - OFF format (if 'v', outputs Voronoi regions)
     G    - Geomview output (2-d, 3-d and 4-d)
     m    - Mathematica output (2-d and 3-d)
     QVn  - print facets that include point n, -n if not
     TO file- output results to file, may be enclosed in single quotes
 
 examples:
     rbox c d D2 | qhull Qc s f Fx | more      rbox 1000 s | qhull Tv s FA
     rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v Qbb Qt p
     rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o
     rbox c | qhull n                          rbox c | qhull FV n | qhull H Fp
     rbox d D12 | qhull QR0 FA                 rbox c D7 | qhull FA TF1000
     rbox y 1000 W0 | qhull                    rbox 10 | qhull v QJ o Fv
 

»qhull input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

Use I/O redirection (e.g., qhull < data.txt), a pipe (e.g., rbox 10 | qhull), or the 'TI' option (e.g., qhull TI data.txt).

Comments start with a non-numeric character. Error reporting is simpler if there is one point per line. Dimension and number of points may be reversed. For halfspace intersection, an interior point may be prepended (see qhalf input).

Here is the input for computing the convex hull of the unit cube. The output is the normals, one per facet.

rbox c > data

 3 RBOX c
 8
   -0.5   -0.5   -0.5
   -0.5   -0.5    0.5
   -0.5    0.5   -0.5
   -0.5    0.5    0.5
    0.5   -0.5   -0.5
    0.5   -0.5    0.5
    0.5    0.5   -0.5
    0.5    0.5    0.5
 

qhull s n < data

 
 Convex hull of 8 points in 3-d:
 
   Number of vertices: 8
   Number of facets: 6
   Number of non-simplicial facets: 6
 
 Statistics for: RBOX c | QHULL s n
 
   Number of points processed: 8
   Number of hyperplanes created: 11
   Number of distance tests for qhull: 35
   Number of merged facets: 6
   Number of distance tests for merging: 84
   CPU seconds to compute hull (after input): 0.081
 
 4
 6
      0      0     -1   -0.5
      0     -1      0   -0.5
      1      0      0   -0.5
     -1      0      0   -0.5
      0      1      0   -0.5
      0      0      1   -0.5
 

»qhull outputs

These options control the output of qhull. They may be used individually or together.

 
General
qhull
compute the convex hull of the input points. See qconvex.
qhull d Qbb
compute the Delaunay triangulation by lifting the points to a paraboloid. Use option 'Qbb' to scale the paraboloid and improve numeric precision. See qdelaunay.
qhull v Qbb
compute the Voronoi diagram by computing the Delaunay triangulation. Use option 'Qbb' to scale the paraboloid and improve numeric precision. See qvoronoi.
qhull H
compute the halfspace intersection about a point via polar duality. See qhalf.

For a full list of output options see

»qhull controls

For a full list of control options see

»qhull options

 qhull- compute convex hulls and related structures.
     http://www.qhull.org
 
 input (stdin):
     first lines: dimension and number of points (or vice-versa).
     other lines: point coordinates, best if one point per line
     comments:    start with a non-numeric character
     halfspaces:  use dim plus one and put offset after coefficients.
                  May be preceded by a single interior point ('H').
 
 options:
     d    - Delaunay triangulation by lifting points to a paraboloid
     d Qu - furthest-site Delaunay triangulation (upper convex hull)
     v    - Voronoi diagram (dual of the Delaunay triangulation)
     v Qu - furthest-site Voronoi diagram
     Hn,n,... - halfspace intersection about point [n,n,0,...]
     Qt   - triangulated output
     QJ   - joggle input instead of merging facets
     Qc   - keep coplanar points with nearest facet
     Qi   - keep interior points with nearest facet
 
 Qhull control options:
     Qbk:n   - scale coord k so that low bound is n
       QBk:n - scale coord k so that upper bound is n (QBk is 0.5)
     QbB  - scale input to unit cube centered at the origin
     Qbb  - scale last coordinate to [0,m] for Delaunay triangulations
     Qbk:0Bk:0 - remove k-th coordinate from input
     QJn  - randomly joggle input in range [-n,n]
     QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
     Qf   - partition point to furthest outside facet
     Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')
     Qm   - only process points that would increase max_outside
     Qr   - process random outside points instead of furthest ones
     Qs   - search all points for the initial simplex
     Qu   - for 'd' or 'v', compute upper hull without point at-infinity
               returns furthest-site Delaunay triangulation
     Qv   - test vertex neighbors for convexity
     Qx   - exact pre-merges (skips coplanar and anglomaniacs facets)
     Qz   - add point-at-infinity to Delaunay triangulation
     QGn  - good facet if visible from point n, -n for not visible
     QVn  - good facet if it includes point n, -n if not
     Q0   - turn off default p remerge with 'C-0'/'Qx'
     Q1     - sort merges by type instead of angle
     Q2   - merge all non-convex at once instead of independent sets
     Q3   - do not merge redundant vertices
     Q4   - avoid old>new merges
     Q5   - do not correct outer planes at end of qhull
     Q6   - do not pre-merge concave or coplanar facets
     Q7   - depth-first processing instead of breadth-first
     Q8   - do not process near-inside points
     Q9   - process furthest of furthest points
     Q10  - no special processing for narrow distributions
         Q11  - copy normals and recompute centrums for tricoplanar facets
 
 Towpaths Trace options:
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
     Tc   - check frequently during execution
     Ts   - print statistics
     Tv   - verify result: structure, convexity, and point inclusion
     Tz   - send all output to stdout
     TFn  - report summary when n or more facets created
     TI file - input data from file, no spaces or single quotes
     TO file - output results to file, may be enclosed in single quotes
     TPn  - turn on tracing when point n added to hull
      TMn - turn on tracing at merge n
      TWn - trace merge facets when width > n
     TRn  - rerun qhull n times.  Use with 'QJn'
     TVn  - stop qhull after adding point n, -n for before (see TCn)
      TCn - stop qhull after building cone for point n (see TVn)
 
 Precision options:
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
     En   - max roundoff error for distance computation
     Rn   - randomly perturb computations by a factor of [1-n,1+n]
     Vn   - min distance above plane for a visible facet (default 3C-n or En)
     Un   - max distance below plane for a new, coplanar point (default Vn)
     Wn   - min facet width for outside point (before roundoff, default 2Vn)
 
 Output formats (may be combined; if none, produces a summary to stdout):
     f    - facet dump
     G    - Geomview output (see below)
     i    - vertices incident to each facet
     m    - Mathematica output (2-d and 3-d)
     o    - OFF format (dim, points and facets; Voronoi regions)
     n    - normals with offsets
     p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')
     s    - summary (stderr)
 
 More formats:
     Fa   - area for each facet
     FA   - compute total area and volume for option 's'
     Fc   - count plus coplanar points for each facet
            use 'Qc' (default) for coplanar and 'Qi' for interior
     FC   - centrum or Voronoi center for each facet
     Fd   - use cdd format for input (homogeneous with offset first)
     FD   - use cdd format for numeric output (offset first)
     FF   - facet dump without ridges
     Fi   - inner plane for each facet
            for 'v', separating hyperplanes for bounded Voronoi regions
     FI   - ID of each facet
     Fm   - merge count for each facet (511 max)
     FM   - Maple output (2-d and 3-d)
     Fn   - count plus neighboring facets for each facet
     FN   - count plus neighboring facets for each point
     Fo   - outer plane (or max_outside) for each facet
            for 'v', separating hyperplanes for unbounded Voronoi regions
     FO   - options and precision constants
     Fp   - dim, count, and intersection coordinates (halfspace only)
     FP   - nearest vertex and distance for each coplanar point
     FQ   - command used for qhull
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                       output: #vertices, #facets, #coplanars, #nonsimplicial
                     #real (2), max outer plane, min vertex
     FS   - sizes:   #int (0)
                     #real(2) tot area, tot volume
     Ft   - triangulation with centrums for non-simplicial facets (OFF format)
     Fv   - count plus vertices for each facet
            for 'v', Voronoi diagram as Voronoi vertices for pairs of sites
     FV   - average of vertices (a feasible point for 'H')
     Fx   - extreme points (in order for 2-d)
 
 Geomview options (2-d, 3-d, and 4-d; 2-d Voronoi)
     Ga   - all points as dots
      Gp  -  coplanar points and vertices as radii
      Gv  -  vertices as spheres
     Gi   - inner planes only
      Gn  -  no planes
      Go  -  outer planes only
     Gc   - centrums
     Gh   - hyperplane intersections
     Gr   - ridges
     GDn  - drop dimension n in 3-d and 4-d output
     Gt   - for 3-d 'd', transparent outer ridges
 
 Print options:
     PAn  - keep n largest facets by area
     Pdk:n - drop facet if normal[k] <= n (default 0.0)
     PDk:n - drop facet if normal[k] >= n
     Pg   - print good facets (needs 'QGn' or 'QVn')
     PFn  - keep facets whose area is at least n
     PG   - print neighbors of good facets
     PMn  - keep n facets with most merges
     Po   - force output.  If error, output neighborhood of facet
     Pp   - do not report precision problems
 
     .    - list of all options
     -    - one line descriptions of all options
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qvoron_f.htm b/html/qvoron_f.htm index 1ffec40..36bdac2 100644 --- a/html/qvoron_f.htm +++ b/html/qvoron_f.htm @@ -1,394 +1,394 @@ qvoronoi Qu -- furthest-site Voronoi diagram Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[delaunay]qvoronoi Qu -- furthest-site Voronoi diagram

The furthest-site Voronoi diagram is the furthest-neighbor map for a set of points. Each region contains those points that are further from one input site than any other input site. See the survey article by Aurenhammer ['91] and the brief introduction by O'Rourke ['94]. The furthest-site Voronoi diagram is the dual of the furthest-site Delaunay triangulation.

Example: rbox 10 D2 | qvoronoi Qu s o TO result
Compute the 2-d, furthest-site Voronoi diagram of 10 random points. Write a summary to the console and the Voronoi regions and vertices to 'result'. The first vertex of the result indicates unbounded regions. Almost all regions are unbounded.
Example: rbox r y c G1 D2 | qvoronoi Qu s Fn TO result
Compute the 2-d furthest-site Voronoi diagram of a square and a small triangle. Write a summary to the console and the Voronoi vertices for each input site to 'result'. The origin is the only furthest-site Voronoi vertex. The negative indices indicate vertices-at-infinity.

Qhull computes the furthest-site Voronoi diagram via the furthest-site Delaunay triangulation. Each furthest-site Voronoi vertex is the circumcenter of an upper facet of the Delaunay triangulation. Each furthest-site Voronoi region corresponds to a vertex of the Delaunay triangulation (i.e., an input site).

See Qhull FAQ - Delaunay and Voronoi diagram questions.

The 'qvonoroi' program is equivalent to 'qhull v Qbb' in 2-d to 3-d, and 'qhull v Qbb Qx' in 4-d and higher. It disables the following Qhull options: d n m v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V Fa FA FC Fp FS Ft FV Gt Q0,etc. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


»furthest-site qvoronoi synopsis

See qvoronoi synopsis. The same program is used for both constructions. Use option 'Qu' for furthest-site Voronoi diagrams.

»furthest-site qvoronoi input

The input data on stdin consists of:

  • dimension
  • number of points
  • point coordinates

Use I/O redirection (e.g., qvoronoi Qu < data.txt), a pipe (e.g., rbox 10 | qvoronoi Qu), or the 'TI' option (e.g., qvoronoi TI data.txt Qu).

For example, this is a square containing four random points. Its furthest-site Voronoi diagram has on vertex and four unbounded, separating hyperplanes (i.e., the coordinate axes)

rbox c 4 D2 > data
 2 RBOX c 4 D2
 8
 -0.4999921736307369 -0.3684622117955817
 0.2556053225468894 -0.0413498678629751
 0.0327672376602583 -0.2810408135699488
 -0.452955383763607 0.17886471718444
   -0.5   -0.5
   -0.5    0.5
    0.5   -0.5
    0.5    0.5
 

qvoronoi Qu s Fo < data

 
 Furthest-site Voronoi vertices by the convex hull of 8 points in 3-d:
 
   Number of Voronoi regions: 8
   Number of Voronoi vertices: 1
   Number of non-simplicial Voronoi vertices: 1
 
 Statistics for: RBOX c 4 D2 | QVORONOI Qu s Fo
 
   Number of points processed: 8
   Number of hyperplanes created: 20
   Number of facets in hull: 11
   Number of distance tests for qhull: 34
   Number of merged facets: 1
   Number of distance tests for merging: 107
   CPU seconds to compute hull (after input):  0
 
 4
 5 4 5      0      1      0
 5 4 6      1      0      0
 5 5 7      1      0      0
 5 6 7      0      1      0
 

» furthest-site qvoronoi outputs

These options control the output of furthest-site Voronoi diagrams.

 
furthest-site Voronoi vertices
p
print the coordinates of the furthest-site Voronoi vertices. The first line is the dimension. The second line is the number of vertices. Each remaining line is a furthest-site Voronoi vertex. The points-in-square example has one furthest-site Voronoi vertex at the origin.
Fn
list the neighboring furthest-site Voronoi vertices for each furthest-site Voronoi vertex. The first line is the number of Voronoi vertices. Each remaining line starts with the number of neighboring vertices. Negative indices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the points-in-square example, the Voronoi vertex at the origin has four neighbors-at-infinity.
FN
list the furthest-site Voronoi vertices for each furthest-site Voronoi region. The first line is the number of Voronoi regions. Each remaining line starts with the number of Voronoi vertices. Negative indices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the points-in-square example, all regions share the Voronoi vertex at the origin.
 
 
furthest-site Voronoi regions
o
print the furthest-site Voronoi regions in OFF format. The first line is the dimension. The second line is the number of vertices, the number of input sites, and "1". The third line represents the vertex-at-infinity. Its coordinates are "-10.101". The next lines are the coordinates of the furthest-site Voronoi vertices. Each remaining line starts with the number of Voronoi vertices in a Voronoi region. In 2-d, the vertices are listed in adjacency order (unoriented). In 3-d and higher, the vertices are listed in numeric order. In the points-in-square example, each unbounded region includes the Voronoi vertex at the origin. Lines consisting of 0 indicate interior input sites.
Fi
print separating hyperplanes for inner, bounded furthest-site Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. The are no bounded, separating hyperplanes for the points-in-square example.
Fo
print separating hyperplanes for outer, unbounded furthest-site Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites on the convex hull. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. The points-in-square example has four unbounded, separating hyperplanes.
 
 
Input sites
Fv
list ridges of furthest-site Voronoi vertices for pairs of input sites. The first line is the number of ridges. Each remaining line starts with two plus the number of Voronoi vertices in the ridge. The next two numbers are two adjacent input sites. The remaining numbers list the Voronoi vertices. As with option 'o', a 0 indicates the vertex-at-infinity and an unbounded, separating hyperplane. The perpendicular bisector (separating hyperplane) of the input sites is a flat through these vertices. In the points-in-square example, the ridge for each edge of the square is unbounded.
 
 
General
s
print summary of the furthest-site Voronoi diagram. Use 'Fs' for numeric data.
i
list input sites for each furthest-site Delaunay region. Use option 'Pp' to avoid the warning. The first line is the number of regions. The remaining lines list the input sites for each region. The regions are oriented. In the points-in-square example, the square region has four input sites. In 3-d and higher, report cospherical sites by adding extra points.
G
Geomview output for 2-d furthest-site Voronoi diagrams.

» furthest-site qvoronoi controls

These options provide additional control:

Qu
must be used.
QVn
select furthest-site Voronoi vertices for input site n
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
TFn
report progress after constructing n facets
PDk:1
include upper and lower facets in the output. Set k to the last dimension (e.g., 'PD2:1' for 2-d inputs).
f
facet dump. Print the data structure for each facet (i.e., furthest-site Voronoi vertex).

» furthest-site qvoronoi graphics

In 2-d, Geomview output ('G') displays a furthest-site Voronoi diagram with extra edges to close the unbounded furthest-site Voronoi regions. All regions will be unbounded. Since the points-in-box example has only one furthest-site Voronoi vertex, the Geomview output is one point.

See the Delaunay and Voronoi examples for a 2-d example. Turn off normalization (on Geomview's 'obscure' menu) when comparing the furthest-site Voronoi diagram with the corresponding Voronoi diagram.

»furthest-site qvoronoi notes

See Voronoi notes.

»furthest-site qvoronoi conventions

The following terminology is used for furthest-site Voronoi diagrams in Qhull. The underlying structure is a furthest-site Delaunay triangulation from a convex hull in one higher dimension. Upper facets of the Delaunay triangulation correspond to vertices of the furthest-site Voronoi diagram. Vertices of the furthest-site Delaunay triangulation correspond to input sites. They also define regions of the furthest-site Voronoi diagram. All vertices are extreme points of the input sites. See qconvex conventions, furthest-site delaunay conventions, and Qhull's data structures.

  • input site - a point in the input (one dimension lower than a point on the convex hull)
  • point - a point has d+1 coordinates. The last coordinate is the sum of the squares of the input site's coordinates
  • vertex - a point on the upper facets of the paraboloid. It corresponds to a unique input site.
  • furthest-site Delaunay facet - an upper facet of the paraboloid. The last coefficient of its normal is clearly positive.
  • furthest-site Voronoi vertex - the circumcenter of a furthest-site Delaunay facet
  • furthest-site Voronoi region - the region of Euclidean space further from an input site than any other input site. Qhull lists the furthest-site Voronoi vertices that define each furthest-site Voronoi region.
  • furthest-site Voronoi diagram - the graph of the furthest-site Voronoi regions with the ridges (edges) between the regions.
  • infinity vertex - the Voronoi vertex for unbounded furthest-site Voronoi regions in 'o' output format. Its coordinates are -10.101.
  • good facet - an furthest-site Voronoi vertex with optional restrictions by 'QVn', etc.

»furthest-site qvoronoi options

See qvoronoi options. The same program is used for both constructions. Use option 'Qu' for furthest-site Voronoi diagrams.

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/html/qvoronoi.htm b/html/qvoronoi.htm index d26d6d2..9a9a64a 100644 --- a/html/qvoronoi.htm +++ b/html/qvoronoi.htm @@ -1,665 +1,665 @@ qvoronoi -- Voronoi diagram Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options

[voronoi]qvoronoi -- Voronoi diagram

The Voronoi diagram is the nearest-neighbor map for a set of points. Each region contains those points that are nearer one input site than any other input site. It has many useful properties and applications. See the survey article by Aurenhammer ['91] and the detailed introduction by O'Rourke ['94]. The Voronoi diagram is the dual of the Delaunay triangulation.

Example: rbox 10 D3 | qvoronoi s o TO result
Compute the 3-d Voronoi diagram of 10 random points. Write a summary to the console and the Voronoi vertices and regions to 'result'. The first vertex of the result indicates unbounded regions.
 
Example: rbox r y c G0.1 D2 | qvoronoi s o TO result
Compute the 2-d Voronoi diagram of a triangle and a small square. Write a summary to the console and Voronoi vertices and regions to 'result'. Report a single Voronoi vertex for cocircular input sites. The first vertex of the result indicates unbounded regions. The origin is the Voronoi vertex for the square.
 
Example: rbox r y c G0.1 D2 | qvoronoi Fv TO result
Compute the 2-d Voronoi diagram of a triangle and a small square. Write a summary to the console and the Voronoi ridges to 'result'. Each ridge is the perpendicular bisector of a pair of input sites. Vertex "0" indicates unbounded ridges. Vertex "8" is the Voronoi vertex for the square.
 
Example: rbox r y c G0.1 D2 | qvoronoi Fi
Print the bounded, separating hyperplanes for the 2-d Voronoi diagram of a triangle and a small square. Note the four hyperplanes (i.e., lines) for Voronoi vertex "8". It is at the origin.

Qhull computes the Voronoi diagram via the Delaunay triangulation. Each Voronoi vertex is the circumcenter of a facet of the Delaunay triangulation. Each Voronoi region corresponds to a vertex (i.e., input site) of the Delaunay triangulation.

Qhull outputs the Voronoi vertices for each Voronoi region. With option 'Fv', it lists all ridges of the Voronoi diagram with the corresponding pairs of input sites. With options 'Fi' and 'Fo', it lists the bounded and unbounded separating hyperplanes. You can also output a single Voronoi region for further processing [see graphics].

Use option 'Qz' if the input is circular, cospherical, or nearly so. It improves precision by adding a point "at infinity," above the corresponding paraboloid.

See Qhull FAQ - Delaunay and Voronoi diagram questions.

The 'qvonoroi' program is equivalent to 'qhull v Qbb' in 2-d to 3-d, and 'qhull v Qbb Qx' in 4-d and higher. It disables the following Qhull options: d n v Qbb QbB Qf Qg Qm Qr QR Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0,etc. -

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber

Voronoi image by KOOK Architecture, Silvan Oesterle and Michael Knauss.


»qvoronoi synopsis

 qvoronoi- compute the Voronoi diagram.
     input (stdin): dimension, number of points, point coordinates
     comments start with a non-numeric character
 
 options (qh-voron.htm):
     Qu   - compute furthest-site Voronoi diagram
     Tv   - verify result: structure, convexity, and in-circle test
     .    - concise list of all options
     -    - one-line description of all options
 
 output options (subset):
     s    - summary of results (default)
     p    - Voronoi vertices
     o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)
     FN   - count and Voronoi vertices for each Voronoi region
     Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites
     Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded
     G    - Geomview output (2-d only)
     QVn  - Voronoi vertices for input point n, -n if not
     TO file- output results to file, may be enclosed in single quotes
 
 examples:
 rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi
 rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv
 rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo
 rbox c G1 d D2 | qvoronoi s p       rbox c P0 D2 | qvoronoi s Fv QV0
 

»qvoronoi input

The input data on stdin consists of:
  • dimension
  • number of points
  • point coordinates

Use I/O redirection (e.g., qvoronoi < data.txt), a pipe (e.g., rbox 10 | qvoronoi), or the 'TI' option (e.g., qvoronoi TI data.txt).

For example, this is four cocircular points inside a square. Their Voronoi diagram has nine vertices and eight regions. Notice the Voronoi vertex at the origin, and the Voronoi vertices (on each axis) for the four sides of the square.

rbox s 4 W0 c G1 D2 > data
 2 RBOX s 4 W0 c D2
 8
 -0.4941988586954018 -0.07594397977563715
 -0.06448037284989526 0.4958248496365813
 0.4911154367094632 0.09383830681375946
 -0.348353580869097 -0.3586778257652367
     -1     -1
     -1      1
      1     -1
      1      1
 

qvoronoi s p < data

 
 Voronoi diagram by the convex hull of 8 points in 3-d:
 
   Number of Voronoi regions: 8
   Number of Voronoi vertices: 9
   Number of non-simplicial Voronoi vertices: 1
 
 Statistics for: RBOX s 4 W0 c D2 | QVORONOI s p
 
   Number of points processed: 8
   Number of hyperplanes created: 18
   Number of facets in hull: 10
   Number of distance tests for qhull: 33
   Number of merged facets: 2
   Number of distance tests for merging: 102
   CPU seconds to compute hull (after input): 0.094
 
 2
 9
 4.217546450968612e-17 1.735507986399734
 -8.402566836762659e-17 -1.364368854147395
 0.3447488772716865 -0.6395484723719818
 1.719446929853986 2.136555906154247e-17
 0.4967882915039657 0.68662371396699
 -1.729928876283549 1.343733067524222e-17
 -0.8906163241424728 -0.4594150543829102
 -0.6656840313875723 0.5003013793414868
 -7.318364664277155e-19 -1.188217818408333e-16
 

» qvoronoi outputs

These options control the output of Voronoi diagrams.

 
Voronoi vertices
p
print the coordinates of the Voronoi vertices. The first line is the dimension. The second line is the number of vertices. Each remaining line is a Voronoi vertex.
Fn
list the neighboring Voronoi vertices for each Voronoi vertex. The first line is the number of Voronoi vertices. Each remaining line starts with the number of neighboring vertices. Negative vertices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the circle-in-box example, the Voronoi vertex at the origin has four neighbors.
FN
list the Voronoi vertices for each Voronoi region. The first line is the number of Voronoi regions. Each remaining line starts with the number of Voronoi vertices. Negative indices (e.g., -1) indicate vertices outside of the Voronoi diagram. In the circle-in-box example, the four bounded regions are defined by four Voronoi vertices.
 
 
Voronoi regions
o
print the Voronoi regions in OFF format. The first line is the dimension. The second line is the number of vertices, the number of input sites, and "1". The third line represents the vertex-at-infinity. Its coordinates are "-10.101". The next lines are the coordinates of the Voronoi vertices. Each remaining line starts with the number of Voronoi vertices in a Voronoi region. In 2-d, the vertices are listed in adjacency order (unoriented). In 3-d and higher, the vertices are listed in numeric order. In the circle-in-square example, each bounded region includes the Voronoi vertex at the origin. Lines consisting of 0 indicate coplanar input sites or 'Qz'.
Fi
print separating hyperplanes for inner, bounded Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. It will list relevant statistics to stderr.
Fo
print separating hyperplanes for outer, unbounded Voronoi regions. The first number is the number of separating hyperplanes. Each remaining line starts with 3+dim. The next two numbers are adjacent input sites on the convex hull. The next dim numbers are the coefficients of the separating hyperplane. The last number is its offset. Use 'Tv' to verify that the hyperplanes are perpendicular bisectors. It will list relevant statistics to stderr,
 
 
Input sites
Fv
list ridges of Voronoi vertices for pairs of input sites. The first line is the number of ridges. Each remaining line starts with two plus the number of Voronoi vertices in the ridge. The next two numbers are two adjacent input sites. The remaining numbers list the Voronoi vertices. As with option 'o', a 0 indicates the vertex-at-infinity and an unbounded, separating hyperplane. The perpendicular bisector (separating hyperplane) of the input sites is a flat through these vertices. In the circle-in-square example, the ridge for each edge of the square is unbounded.
Fc
list coincident input sites for each Voronoi vertex. The first line is the number of vertices. The remaining lines start with the number of coincident sites and deleted vertices. Deleted vertices indicate highly degenerate input (see'Fs'). A coincident site is assigned to one Voronoi vertex. Do not use 'QJ' with 'Fc'; the joggle will separate coincident sites.
FP
print coincident input sites with distance to nearest site (i.e., vertex). The first line is the number of coincident sites. Each remaining line starts with the point ID of an input site, followed by the point ID of a coincident point, its vertex, and distance. Includes deleted vertices which indicate highly degenerate input (see'Fs'). Do not use 'QJ' with 'FP'; the joggle will separate coincident sites.
 
 
General
s
print summary of the Voronoi diagram. Use 'Fs' for numeric data.
i
list input sites for each Delaunay region. Use option 'Pp' to avoid the warning. The first line is the number of regions. The remaining lines list the input sites for each region. The regions are oriented. In the circle-in-square example, the cocircular region has four edges. In 3-d and higher, report cospherical sites by adding extra points.
G
Geomview output for 2-d Voronoi diagrams.

» qvoronoi controls

These options provide additional control:

Qu
compute the furthest-site Voronoi diagram.
QVn
select Voronoi vertices for input site n
Qz
add a point above the paraboloid to reduce precision errors. Use it for nearly cocircular/cospherical input (e.g., 'rbox c | qvoronoi Qz').
Tv
verify result
TI file
input data from file. The filename may not use spaces or quotes.
TO file
output results to file. Use single quotes if the filename contains spaces (e.g., TO 'file with spaces.txt'
TFn
report progress after constructing n facets
PDk:1
include upper and lower facets in the output. Set k to the last dimension (e.g., 'PD2:1' for 2-d inputs).
f
facet dump. Print the data structure for each facet (i.e., Voronoi vertex).

» qvoronoi graphics

In 2-d, Geomview output ('G') displays a Voronoi diagram with extra edges to close the unbounded Voronoi regions. To view the unbounded rays, enclose the input points in a square.

You can also view individual Voronoi regions in 3-d. To view the Voronoi region for site 3 in Geomview, execute

qvoronoi <data QV3 p | qconvex s G >output

The qvoronoi command returns the Voronoi vertices for input site 3. The qconvex command computes their convex hull. This is the Voronoi region for input site 3. Its hyperplane normals (qconvex 'n') are the same as the separating hyperplanes from options 'Fi' and 'Fo' (up to roundoff error).

See the Delaunay and Voronoi examples for 2-d and 3-d examples. Turn off normalization (on Geomview's 'obscure' menu) when comparing the Voronoi diagram with the corresponding Delaunay triangulation.

»qvoronoi notes

You can simplify the Voronoi diagram by enclosing the input sites in a large square or cube. This is particularly recommended for cocircular or cospherical input data.

See Voronoi graphics for computing the convex hull of a Voronoi region.

Voronoi diagrams do not include facets that are coplanar with the convex hull of the input sites. A facet is coplanar if the last coefficient of its normal is nearly zero (see qh_ZEROdelaunay).

Unbounded regions can be confusing. For example, 'rbox c | qvoronoi Qz o' produces the Voronoi regions for the vertices of a cube centered at the origin. All regions are unbounded. The output is

3
 2 9 1
 -10.101 -10.101 -10.101
      0      0      0
 2 0 1
 2 0 1
 2 0 1
 2 0 1
 2 0 1
 2 0 1
 2 0 1
 2 0 1
 0
 

The first line is the dimension. The second line is the number of vertices and the number of regions. There is one region per input point plus a region for the point-at-infinity added by option 'Qz'. The next two lines lists the Voronoi vertices. The first vertex is the infinity vertex. It is indicate by the coordinates -10.101. The second vertex is the origin. The next nine lines list the regions. Each region lists two vertices -- the infinity vertex and the origin. The last line is "0" because no region is associated with the point-at-infinity. A "0" would also be listed for nearly incident input sites.

To use option 'Fv', add an interior point. For example,

 rbox c P0 | qvoronoi Fv
 20
 5 0 7 1 3 5
 5 0 3 1 4 5
 5 0 5 1 2 3
 5 0 1 1 2 4
 5 0 6 2 3 6
 5 0 2 2 4 6
 5 0 4 4 5 6
 5 0 8 5 3 6
 5 1 2 0 2 4
 5 1 3 0 1 4
 5 1 5 0 1 2
 5 2 4 0 4 6
 5 2 6 0 2 6
 5 3 4 0 4 5
 5 3 7 0 1 5
 5 4 8 0 6 5
 5 5 6 0 2 3
 5 5 7 0 1 3
 5 6 8 0 6 3
 5 7 8 0 3 5
 

The output consists of 20 ridges and each ridge lists a pair of input sites and a triplet of Voronoi vertices. The first eight ridges connect the origin ('P0'). The remainder list the edges of the cube. Each edge generates an unbounded ray through the midpoint. The corresponding separating planes ('Fo') follow each pair of coordinate axes.

Options 'Qt' (triangulated output) and 'QJ' (joggled input) are deprecated. They may produce unexpected results. If you use these options, cocircular and cospherical input sites will produce duplicate or nearly duplicate Voronoi vertices. See also Merged facets or joggled input.

»qvoronoi conventions

The following terminology is used for Voronoi diagrams in Qhull. The underlying structure is a Delaunay triangulation from a convex hull in one higher dimension. Facets of the Delaunay triangulation correspond to vertices of the Voronoi diagram. Vertices of the Delaunay triangulation correspond to input sites. They also correspond to regions of the Voronoi diagram. See convex hull conventions, Delaunay conventions, and Qhull's data structures.

  • input site - a point in the input (one dimension lower than a point on the convex hull)
  • point - a point has d+1 coordinates. The last coordinate is the sum of the squares of the input site's coordinates
  • coplanar point - a nearly incident input site
  • vertex - a point on the paraboloid. It corresponds to a unique input site.
  • point-at-infinity - a point added above the paraboloid by option 'Qz'
  • Delaunay facet - a lower facet of the paraboloid. The last coefficient of its normal is clearly negative.
  • Voronoi vertex - the circumcenter of a Delaunay facet
  • Voronoi region - the Voronoi vertices for an input site. The region of Euclidean space nearest to an input site.
  • Voronoi diagram - the graph of the Voronoi regions. It includes the ridges (i.e., edges) between the regions.
  • vertex-at-infinity - the Voronoi vertex that indicates unbounded Voronoi regions in 'o' output format. Its coordinates are -10.101.
  • good facet - a Voronoi vertex with optional restrictions by 'QVn', etc.

»qvoronoi options

 qvoronoi- compute the Voronoi diagram
     http://www.qhull.org
 
 input (stdin):
     first lines: dimension and number of points (or vice-versa).
     other lines: point coordinates, best if one point per line
     comments:    start with a non-numeric character
 
 options:
     Qu   - compute furthest-site Voronoi diagram
 
 Qhull control options:
     QJn  - randomly joggle input in range [-n,n]
     Qs   - search all points for the initial simplex
     Qz   - add point-at-infinity to Voronoi diagram
     QGn  - Voronoi vertices if visible from point n, -n if not
     QVn  - Voronoi vertices for input point n, -n if not
 
 Trace options:
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events
     Tc   - check frequently during execution
     Ts   - statistics
     Tv   - verify result: structure, convexity, and in-circle test
     Tz   - send all output to stdout
     TFn  - report summary when n or more facets created
     TI file - input data from file, no spaces or single quotes
     TO file - output results to file, may be enclosed in single quotes
     TPn  - turn on tracing when point n added to hull
      TMn - turn on tracing at merge n
      TWn - trace merge facets when width > n
     TVn  - stop qhull after adding point n, -n for before (see TCn)
      TCn - stop qhull after building cone for point n (see TVn)
 
 Precision options:
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
     Rn   - randomly perturb computations by a factor of [1-n,1+n]
     Wn   - min facet width for non-coincident point (before roundoff)
 
 Output formats (may be combined; if none, produces a summary to stdout):
     s    - summary to stderr
     p    - Voronoi vertices
     o    - OFF format (dim, Voronoi vertices, and Voronoi regions)
     i    - Delaunay regions (use 'Pp' to avoid warning)
     f    - facet dump
 
 More formats:
     Fc   - count plus coincident points (by Voronoi vertex)
     Fd   - use cdd format for input (homogeneous with offset first)
     FD   - use cdd format for output (offset first)
     FF   - facet dump without ridges
     Fi   - separating hyperplanes for bounded Voronoi regions
     FI   - ID for each Voronoi vertex
     Fm   - merge count for each Voronoi vertex (511 max)
     Fn   - count plus neighboring Voronoi vertices for each Voronoi vertex
     FN   - count and Voronoi vertices for each Voronoi region
     Fo   - separating hyperplanes for unbounded Voronoi regions
     FO   - options and precision constants
     FP   - nearest point and distance for each coincident point
     FQ   - command used for qvoronoi
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,
                     for output: #Voronoi regions, #Voronoi vertices,
                                 #coincident points, #non-simplicial regions
                     #real (2), max outer plane and min vertex
     Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites
     Fx   - extreme points of Delaunay triangulation (on convex hull)
 
 Geomview options (2-d only)
     Ga   - all points as dots
      Gp  -  coplanar points and vertices as radii
      Gv  -  vertices as spheres
     Gi   - inner planes only
      Gn  -  no planes
      Go  -  outer planes only
     Gc   - centrums
     Gh   - hyperplane intersections
     Gr   - ridges
     GDn  - drop dimension n in 3-d and 4-d output
 
 Print options:
     PAn  - keep n largest Voronoi vertices by 'area'
     Pdk:n - drop facet if normal[k] <= n (default 0.0)
     PDk:n - drop facet if normal[k] >= n
     Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')
     PFn  - keep Voronoi vertices whose 'area' is at least n
     PG   - print neighbors of good Voronoi vertices
     PMn  - keep n Voronoi vertices with most merges
     Po   - force output.  If error, output neighborhood of facet
     Pp   - do not report precision problems
 
     .    - list of all options
     -    - one line descriptions of all options
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
To: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
To: synopsis • input • outputs • controls • graphics • notes • conventions • options


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: Sept. 25, 1995 --- Last modified: see top

diff --git a/src/libqhull/geom.c b/src/libqhull/geom.c index 83edd4f..6b16f80 100644 --- a/src/libqhull/geom.c +++ b/src/libqhull/geom.c @@ -1,1234 +1,1234 @@ /*
  ---------------------------------
 
    geom.c
    geometric routines of qhull
 
    see qh-geom.htm and geom.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/geom.c#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/geom.c#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    infrequent code goes into geom2.c
 */
 
 #include "qhull_a.h"
 
 /*---------------------------------
 
   qh_distplane( point, facet, dist )
     return distance from point to facet
 
   returns:
     dist
     if qh.RANDOMdist, joggles result
 
   notes:
     dist > 0 if point is above facet (i.e., outside)
     does not error (for qh_sortfacets, qh_outerinner)
 
   see:
     qh_distnorm in geom2.c
     qh_distplane [geom.c], QhullFacet::distance, and QhullHyperplane::distance are copies
 */
 void qh_distplane(pointT *point, facetT *facet, realT *dist) {
   coordT *normal= facet->normal, *coordp, randr;
   int k;
 
   switch (qh hull_dim){
   case 2:
     *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
     break;
   case 3:
     *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
     break;
   case 4:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
     break;
   case 5:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
     break;
   case 6:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
     break;
   case 7:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
     break;
   case 8:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
     break;
   default:
     *dist= facet->offset;
     coordp= point;
     for (k=qh hull_dim; k--; )
       *dist += *coordp++ * *normal++;
     break;
   }
   zinc_(Zdistplane);
   if (!qh RANDOMdist && qh IStracing < 4)
     return;
   if (qh RANDOMdist) {
     randr= qh_RANDOMint;
     *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
       qh RANDOMfactor * qh MAXabs_coord;
   }
   if (qh IStracing >= 4) {
     qh_fprintf(qh ferr, 8001, "qh_distplane: ");
     qh_fprintf(qh ferr, 8002, qh_REAL_1, *dist);
     qh_fprintf(qh ferr, 8003, "from p%d to f%d\n", qh_pointid(point), facet->id);
   }
   return;
 } /* distplane */
 
 
 /*---------------------------------
 
   qh_findbest( point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
     find facet that is furthest below a point
     for upperDelaunay facets
       returns facet only if !qh_NOupper and clearly above
 
   input:
     starts search at 'startfacet' (can not be flipped)
     if !bestoutside(qh_ALL), stops at qh.MINoutside
 
   returns:
     best facet (reports error if NULL)
     early out if isoutside defined and bestdist > qh.MINoutside
     dist is distance to facet
     isoutside is true if point is outside of facet
     numpart counts the number of distance tests
 
   see also:
     qh_findbestnew()
 
   notes:
     If merging (testhorizon), searches horizon facets of coplanar best facets because
     after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
       avoid calls to distplane, function calls, and real number operations.
     caller traces result
     Optimized for outside points.   Tried recording a search set for qh_findhorizon.
     Made code more complicated.
 
   when called by qh_partitionvisible():
     indicated by qh_ISnewfacets
     qh.newfacet_list is list of simplicial, new facets
     qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
     qh.bestfacet_notsharp set if qh_sharpnewfacets returns False
 
   when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),
                  qh_check_bestdist(), qh_addpoint()
     indicated by !qh_ISnewfacets
     returns best facet in neighborhood of given facet
       this is best facet overall if dist > -   qh.MAXcoplanar
         or hull has at least a "spherical" curvature
 
   design:
     initialize and test for early exit
     repeat while there are better facets
       for each neighbor of facet
         exit if outside facet found
         test for better facet
     if point is inside and partitioning
       test for new facets with a "sharp" intersection
       if so, future calls go to qh_findbestnew()
     test horizon facets
 */
 facetT *qh_findbest(pointT *point, facetT *startfacet,
                      boolT bestoutside, boolT isnewfacets, boolT noupper,
                      realT *dist, boolT *isoutside, int *numpart) {
   realT bestdist= -REALmax/2 /* avoid underflow */;
   facetT *facet, *neighbor, **neighborp;
   facetT *bestfacet= NULL, *lastfacet= NULL;
   int oldtrace= qh IStracing;
   unsigned int visitid= ++qh visit_id;
   int numpartnew=0;
   boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
 
   zinc_(Zfindbest);
   if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid(point))) {
     if (qh TRACElevel > qh IStracing)
       qh IStracing= qh TRACElevel;
     qh_fprintf(qh ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n",
              qh_pointid(point), startfacet->id, isnewfacets, bestoutside, qh MINoutside);
     qh_fprintf(qh ferr, 8005, "  testhorizon? %d noupper? %d", testhorizon, noupper);
     qh_fprintf(qh ferr, 8006, "  Last point added was p%d.", qh furthest_id);
     qh_fprintf(qh ferr, 8007, "  Last merge was #%d.  max_outside %2.2g\n", zzval_(Ztotmerge), qh max_outside);
   }
   if (isoutside)
     *isoutside= True;
   if (!startfacet->flipped) {  /* test startfacet */
     *numpart= 1;
     qh_distplane(point, startfacet, dist);  /* this code is duplicated below */
     if (!bestoutside && *dist >= qh MINoutside
     && (!startfacet->upperdelaunay || !noupper)) {
       bestfacet= startfacet;
       goto LABELreturn_best;
     }
     bestdist= *dist;
     if (!startfacet->upperdelaunay) {
       bestfacet= startfacet;
     }
   }else
     *numpart= 0;
   startfacet->visitid= visitid;
   facet= startfacet;
   while (facet) {
     trace4((qh ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
                 facet->id, bestdist, getid_(bestfacet)));
     lastfacet= facet;
     FOREACHneighbor_(facet) {
       if (!neighbor->newfacet && isnewfacets)
         continue;
       if (neighbor->visitid == visitid)
         continue;
       neighbor->visitid= visitid;
       if (!neighbor->flipped) {  /* code duplicated above */
         (*numpart)++;
         qh_distplane(point, neighbor, dist);
         if (*dist > bestdist) {
           if (!bestoutside && *dist >= qh MINoutside
           && (!neighbor->upperdelaunay || !noupper)) {
             bestfacet= neighbor;
             goto LABELreturn_best;
           }
           if (!neighbor->upperdelaunay) {
             bestfacet= neighbor;
             bestdist= *dist;
             break; /* switch to neighbor */
           }else if (!bestfacet) {
             bestdist= *dist;
             break; /* switch to neighbor */
           }
         } /* end of *dist>bestdist */
       } /* end of !flipped */
     } /* end of FOREACHneighbor */
     facet= neighbor;  /* non-NULL only if *dist>bestdist */
   } /* end of while facet (directed search) */
   if (isnewfacets) {
     if (!bestfacet) {
       bestdist= -REALmax/2;
       bestfacet= qh_findbestnew(point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew);
       testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
     }else if (!qh findbest_notsharp && bestdist < - qh DISTround) {
       if (qh_sharpnewfacets()) {
         /* seldom used, qh_findbestnew will retest all facets */
         zinc_(Zfindnewsharp);
         bestfacet= qh_findbestnew(point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
         testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
         qh findbestnew= True;
       }else
         qh findbest_notsharp= True;
     }
   }
   if (!bestfacet)
     bestfacet= qh_findbestlower(lastfacet, point, &bestdist, numpart);
   if (testhorizon)
     bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
   *dist= bestdist;
   if (isoutside && bestdist < qh MINoutside)
     *isoutside= False;
 LABELreturn_best:
   zadd_(Zfindbesttot, *numpart);
   zmax_(Zfindbestmax, *numpart);
   (*numpart) += numpartnew;
   qh IStracing= oldtrace;
   return bestfacet;
 }  /* findbest */
 
 
 /*---------------------------------
 
   qh_findbesthorizon( qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
     search coplanar and better horizon facets from startfacet/bestdist
     ischeckmax turns off statistics and minsearch update
     all arguments must be initialized
   returns(ischeckmax):
     best facet
   returns(!ischeckmax):
     best facet that is not upperdelaunay
     allows upperdelaunay that is clearly outside
   returns:
     bestdist is distance to bestfacet
     numpart -- updates number of distance tests
 
   notes:
     no early out -- use qh_findbest() or qh_findbestnew()
     Searches coplanar or better horizon facets
 
   when called by qh_check_maxout() (qh_IScheckmax)
     startfacet must be closest to the point
       Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
       even though other facets are below the point.
     updates facet->maxoutside for good, visited facets
     may return NULL
 
     searchdist is qh.max_outside + 2 * DISTround
       + max( MINvisible('Vn'), MAXcoplanar('Un'));
     This setting is a guess.  It must be at least max_outside + 2*DISTround
     because a facet may have a geometric neighbor across a vertex
 
   design:
     for each horizon facet of coplanar best facets
       continue if clearly inside
       unless upperdelaunay or clearly outside
          update best facet
 */
 facetT *qh_findbesthorizon(boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
   facetT *bestfacet= startfacet;
   realT dist;
   facetT *neighbor, **neighborp, *facet;
   facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */
   int numpartinit= *numpart, coplanarfacetset_size;
   unsigned int visitid= ++qh visit_id;
   boolT newbest= False; /* for tracing */
   realT minsearch, searchdist;  /* skip facets that are too far from point */
 
   if (!ischeckmax) {
     zinc_(Zfindhorizon);
   }else {
 #if qh_MAXoutside
     if ((!qh ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
       startfacet->maxoutside= *bestdist;
 #endif
   }
   searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */
   minsearch= *bestdist - searchdist;
   if (ischeckmax) {
     /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
     minimize_(minsearch, -searchdist);
   }
   coplanarfacetset_size= 0;
   facet= startfacet;
   while (True) {
     trace4((qh ferr, 4002, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n",
                 facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
                 minsearch, searchdist));
     FOREACHneighbor_(facet) {
       if (neighbor->visitid == visitid)
         continue;
       neighbor->visitid= visitid;
       if (!neighbor->flipped) {
         qh_distplane(point, neighbor, &dist);
         (*numpart)++;
         if (dist > *bestdist) {
           if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh MINoutside)) {
             bestfacet= neighbor;
             *bestdist= dist;
             newbest= True;
             if (!ischeckmax) {
               minsearch= dist - searchdist;
               if (dist > *bestdist + searchdist) {
                 zinc_(Zfindjump);  /* everything in qh.coplanarfacetset at least searchdist below */
                 coplanarfacetset_size= 0;
               }
             }
           }
         }else if (dist < minsearch)
           continue;  /* if ischeckmax, dist can't be positive */
 #if qh_MAXoutside
         if (ischeckmax && dist > neighbor->maxoutside)
           neighbor->maxoutside= dist;
 #endif
       } /* end of !flipped */
       if (nextfacet) {
         if (!coplanarfacetset_size++) {
           SETfirst_(qh coplanarfacetset)= nextfacet;
           SETtruncate_(qh coplanarfacetset, 1);
         }else
           qh_setappend(&qh coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
                                                  and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
       }
       nextfacet= neighbor;
     } /* end of EACHneighbor */
     facet= nextfacet;
     if (facet)
       nextfacet= NULL;
     else if (!coplanarfacetset_size)
       break;
     else if (!--coplanarfacetset_size) {
       facet= SETfirstt_(qh coplanarfacetset, facetT);
       SETtruncate_(qh coplanarfacetset, 0);
     }else
       facet= (facetT*)qh_setdellast(qh coplanarfacetset);
   } /* while True, for each facet in qh.coplanarfacetset */
   if (!ischeckmax) {
     zadd_(Zfindhorizontot, *numpart - numpartinit);
     zmax_(Zfindhorizonmax, *numpart - numpartinit);
     if (newbest)
       zinc_(Zparthorizon);
   }
   trace4((qh ferr, 4003, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));
   return bestfacet;
 }  /* findbesthorizon */
 
 /*---------------------------------
 
   qh_findbestnew( point, startfacet, dist, isoutside, numpart )
     find best newfacet for point
     searches all of qh.newfacet_list starting at startfacet
     searches horizon facets of coplanar best newfacets
     searches all facets if startfacet == qh.facet_list
   returns:
     best new or horizon facet that is not upperdelaunay
     early out if isoutside and not 'Qf'
     dist is distance to facet
     isoutside is true if point is outside of facet
     numpart is number of distance tests
 
   notes:
     Always used for merged new facets (see qh_USEfindbestnew)
     Avoids upperdelaunay facet unless (isoutside and outside)
 
     Uses qh.visit_id, qh.coplanarfacetset.
     If share visit_id with qh_findbest, coplanarfacetset is incorrect.
 
     If merging (testhorizon), searches horizon facets of coplanar best facets because
     a point maybe coplanar to the bestfacet, below its horizon facet,
     and above a horizon facet of a coplanar newfacet.  For example,
       rbox 1000 s Z1 G1e-13 | qhull
       rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc
 
     qh_findbestnew() used if
        qh_sharpnewfacets -- newfacets contains a sharp angle
        if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)
 
   see also:
     qh_partitionall() and qh_findbest()
 
   design:
     for each new facet starting from startfacet
       test distance from point to facet
       return facet if clearly outside
       unless upperdelaunay and a lowerdelaunay exists
          update best facet
     test horizon facets
 */
 facetT *qh_findbestnew(pointT *point, facetT *startfacet,
            realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
   realT bestdist= -REALmax/2;
   facetT *bestfacet= NULL, *facet;
   int oldtrace= qh IStracing, i;
   unsigned int visitid= ++qh visit_id;
   realT distoutside= 0.0;
   boolT isdistoutside; /* True if distoutside is defined */
   boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
 
   if (!startfacet) {
     if (qh MERGING)
       qh_fprintf(qh ferr, 6001, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
     else
       qh_fprintf(qh ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
               qh furthest_id);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   zinc_(Zfindnew);
   if (qh BESToutside || bestoutside)
     isdistoutside= False;
   else {
     isdistoutside= True;
     distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
   }
   if (isoutside)
     *isoutside= True;
   *numpart= 0;
   if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid(point))) {
     if (qh TRACElevel > qh IStracing)
       qh IStracing= qh TRACElevel;
     qh_fprintf(qh ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",
              qh_pointid(point), startfacet->id, isdistoutside, distoutside);
     qh_fprintf(qh ferr, 8009, "  Last point added p%d visitid %d.",  qh furthest_id, visitid);
     qh_fprintf(qh ferr, 8010, "  Last merge was #%d.\n", zzval_(Ztotmerge));
   }
   /* visit all new facets starting with startfacet, maybe qh facet_list */
   for (i=0, facet=startfacet; i < 2; i++, facet= qh newfacet_list) {
     FORALLfacet_(facet) {
       if (facet == startfacet && i)
         break;
       facet->visitid= visitid;
       if (!facet->flipped) {
         qh_distplane(point, facet, dist);
         (*numpart)++;
         if (*dist > bestdist) {
           if (!facet->upperdelaunay || *dist >= qh MINoutside) {
             bestfacet= facet;
             if (isdistoutside && *dist >= distoutside)
               goto LABELreturn_bestnew;
             bestdist= *dist;
           }
         }
       } /* end of !flipped */
     } /* FORALLfacet from startfacet or qh newfacet_list */
   }
   if (testhorizon || !bestfacet)
     bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,
                                         !qh_NOupper, &bestdist, numpart);
   *dist= bestdist;
   if (isoutside && *dist < qh MINoutside)
     *isoutside= False;
 LABELreturn_bestnew:
   zadd_(Zfindnewtot, *numpart);
   zmax_(Zfindnewmax, *numpart);
   trace4((qh ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));
   qh IStracing= oldtrace;
   return bestfacet;
 }  /* findbestnew */
 
 /* ============ hyperplane functions -- keep code together [?] ============ */
 
 /*---------------------------------
 
   qh_backnormal( rows, numrow, numcol, sign, normal, nearzero )
     given an upper-triangular rows array and a sign,
     solve for normal equation x using back substitution over rows U
 
   returns:
      normal= x
 
      if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),
        if fails on last row
          this means that the hyperplane intersects [0,..,1]
          sets last coordinate of normal to sign
        otherwise
          sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
          sets nearzero
 
   notes:
      assumes numrow == numcol-1
 
      see Golub & van Loan 4.4-9 for back substitution
 
      solves Ux=b where Ax=b and PA=LU
      b= [0,...,0,sign or 0]  (sign is either -1 or +1)
      last row of A= [0,...,0,1]
 
      1) Ly=Pb == y=b since P only permutes the 0's of   b
 
   design:
     for each row from end
       perform back substitution
       if near zero
         use qh_divzero for division
         if zero divide and not last row
           set tail of normal to 0
 */
 void qh_backnormal(realT **rows, int numrow, int numcol, boolT sign,
         coordT *normal, boolT *nearzero) {
   int i, j;
   coordT *normalp, *normal_tail, *ai, *ak;
   realT diagonal;
   boolT waszero;
   int zerocol= -1;
 
   normalp= normal + numcol - 1;
   *normalp--= (sign ? -1.0 : 1.0);
   for (i=numrow; i--; ) {
     *normalp= 0.0;
     ai= rows[i] + i + 1;
     ak= normalp+1;
     for (j=i+1; j < numcol; j++)
       *normalp -= *ai++ * *ak++;
     diagonal= (rows[i])[i];
     if (fabs_(diagonal) > qh MINdenom_2)
       *(normalp--) /= diagonal;
     else {
       waszero= False;
       *normalp= qh_divzero(*normalp, diagonal, qh MINdenom_1_2, &waszero);
       if (waszero) {
         zerocol= i;
         *(normalp--)= (sign ? -1.0 : 1.0);
         for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
           *normal_tail= 0.0;
       }else
         normalp--;
     }
   }
   if (zerocol != -1) {
     zzinc_(Zback0);
     *nearzero= True;
     trace4((qh ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));
     qh_precision("zero diagonal on back substitution");
   }
 } /* backnormal */
 
 /*---------------------------------
 
   qh_gausselim( rows, numrow, numcol, sign )
     Gaussian elimination with partial pivoting
 
   returns:
     rows is upper triangular (includes row exchanges)
     flips sign for each row exchange
     sets nearzero if pivot[k] < qh.NEARzero[k], else clears it
 
   notes:
     if nearzero, the determinant's sign may be incorrect.
     assumes numrow <= numcol
 
   design:
     for each row
       determine pivot and exchange rows if necessary
       test for near zero
       perform gaussian elimination step
 */
 void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
   realT *ai, *ak, *rowp, *pivotrow;
   realT n, pivot, pivot_abs= 0.0, temp;
   int i, j, k, pivoti, flip=0;
 
   *nearzero= False;
   for (k=0; k < numrow; k++) {
     pivot_abs= fabs_((rows[k])[k]);
     pivoti= k;
     for (i=k+1; i < numrow; i++) {
       if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
         pivot_abs= temp;
         pivoti= i;
       }
     }
     if (pivoti != k) {
       rowp= rows[pivoti];
       rows[pivoti]= rows[k];
       rows[k]= rowp;
       *sign ^= 1;
       flip ^= 1;
     }
     if (pivot_abs <= qh NEARzero[k]) {
       *nearzero= True;
       if (pivot_abs == 0.0) {   /* remainder of column == 0 */
         if (qh IStracing >= 4) {
           qh_fprintf(qh ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh DISTround);
           qh_printmatrix(qh ferr, "Matrix:", rows, numrow, numcol);
         }
         zzinc_(Zgauss0);
         qh_precision("zero pivot for Gaussian elimination");
         goto LABELnextcol;
       }
     }
     pivotrow= rows[k] + k;
     pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
     for (i=k+1; i < numrow; i++) {
       ai= rows[i] + k;
       ak= pivotrow;
       n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
       for (j= numcol - (k+1); j--; )
         *ai++ -= n * *ak++;
     }
   LABELnextcol:
     ;
   }
   wmin_(Wmindenom, pivot_abs);  /* last pivot element */
   if (qh IStracing >= 5)
     qh_printmatrix(qh ferr, "qh_gausselem: result", rows, numrow, numcol);
 } /* gausselim */
 
 
 /*---------------------------------
 
   qh_getangle( vect1, vect2 )
     returns the dot product of two vectors
     if qh.RANDOMdist, joggles result
 
   notes:
     the angle may be > 1.0 or < -1.0 because of roundoff errors
 
 */
 realT qh_getangle(pointT *vect1, pointT *vect2) {
   realT angle= 0, randr;
   int k;
 
   for (k=qh hull_dim; k--; )
     angle += *vect1++ * *vect2++;
   if (qh RANDOMdist) {
     randr= qh_RANDOMint;
     angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
       qh RANDOMfactor;
   }
   trace4((qh ferr, 4006, "qh_getangle: %2.2g\n", angle));
   return(angle);
 } /* getangle */
 
 
 /*---------------------------------
 
   qh_getcenter( vertices )
     returns arithmetic center of a set of vertices as a new point
 
   notes:
     allocates point array for center
 */
 pointT *qh_getcenter(setT *vertices) {
   int k;
   pointT *center, *coord;
   vertexT *vertex, **vertexp;
   int count= qh_setsize(vertices);
 
   if (count < 2) {
     qh_fprintf(qh ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   center= (pointT *)qh_memalloc(qh normal_size);
   for (k=0; k < qh hull_dim; k++) {
     coord= center+k;
     *coord= 0.0;
     FOREACHvertex_(vertices)
       *coord += vertex->point[k];
     *coord /= count;
   }
   return(center);
 } /* getcenter */
 
 
 /*---------------------------------
 
   qh_getcentrum( facet )
     returns the centrum for a facet as a new point
 
   notes:
     allocates the centrum
 */
 pointT *qh_getcentrum(facetT *facet) {
   realT dist;
   pointT *centrum, *point;
 
   point= qh_getcenter(facet->vertices);
   zzinc_(Zcentrumtests);
   qh_distplane(point, facet, &dist);
   centrum= qh_projectpoint(point, facet, dist);
   qh_memfree(point, qh normal_size);
   trace4((qh ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
           facet->id, qh_setsize(facet->vertices), dist));
   return centrum;
 } /* getcentrum */
 
 
 /*---------------------------------
 
   qh_getdistance( facet, neighbor, mindist, maxdist )
     returns the maxdist and mindist distance of any vertex from neighbor
 
   returns:
     the max absolute value
 
   design:
     for each vertex of facet that is not in neighbor
       test the distance from vertex to neighbor
 */
 realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {
   vertexT *vertex, **vertexp;
   realT dist, maxd, mind;
 
   FOREACHvertex_(facet->vertices)
     vertex->seen= False;
   FOREACHvertex_(neighbor->vertices)
     vertex->seen= True;
   mind= 0.0;
   maxd= 0.0;
   FOREACHvertex_(facet->vertices) {
     if (!vertex->seen) {
       zzinc_(Zbestdist);
       qh_distplane(vertex->point, neighbor, &dist);
       if (dist < mind)
         mind= dist;
       else if (dist > maxd)
         maxd= dist;
     }
   }
   *mindist= mind;
   *maxdist= maxd;
   mind= -mind;
   if (maxd > mind)
     return maxd;
   else
     return mind;
 } /* getdistance */
 
 
 /*---------------------------------
 
   qh_normalize( normal, dim, toporient )
     normalize a vector and report if too small
     does not use min norm
 
   see:
     qh_normalize2
 */
 void qh_normalize(coordT *normal, int dim, boolT toporient) {
   qh_normalize2( normal, dim, toporient, NULL, NULL);
 } /* normalize */
 
 /*---------------------------------
 
   qh_normalize2( normal, dim, toporient, minnorm, ismin )
     normalize a vector and report if too small
     qh.MINdenom/MINdenom1 are the upper limits for divide overflow
 
   returns:
     normalized vector
     flips sign if !toporient
     if minnorm non-NULL,
       sets ismin if normal < minnorm
 
   notes:
     if zero norm
        sets all elements to sqrt(1.0/dim)
     if divide by zero (divzero())
        sets largest element to   +/-1
        bumps Znearlysingular
 
   design:
     computes norm
     test for minnorm
     if not near zero
       normalizes normal
     else if zero norm
       sets normal to standard value
     else
       uses qh_divzero to normalize
       if nearzero
         sets norm to direction of maximum value
 */
 void qh_normalize2(coordT *normal, int dim, boolT toporient,
             realT *minnorm, boolT *ismin) {
   int k;
   realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
   boolT zerodiv;
 
   norm1= normal+1;
   norm2= normal+2;
   norm3= normal+3;
   if (dim == 2)
     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
   else if (dim == 3)
     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
   else if (dim == 4) {
     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
                + (*norm3)*(*norm3));
   }else if (dim > 4) {
     norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
                + (*norm3)*(*norm3);
     for (k=dim-4, colp=normal+4; k--; colp++)
       norm += (*colp) * (*colp);
     norm= sqrt(norm);
   }
   if (minnorm) {
     if (norm < *minnorm)
       *ismin= True;
     else
       *ismin= False;
   }
   wmin_(Wmindenom, norm);
   if (norm > qh MINdenom) {
     if (!toporient)
       norm= -norm;
     *normal /= norm;
     *norm1 /= norm;
     if (dim == 2)
       ; /* all done */
     else if (dim == 3)
       *norm2 /= norm;
     else if (dim == 4) {
       *norm2 /= norm;
       *norm3 /= norm;
     }else if (dim >4) {
       *norm2 /= norm;
       *norm3 /= norm;
       for (k=dim-4, colp=normal+4; k--; )
         *colp++ /= norm;
     }
   }else if (norm == 0.0) {
     temp= sqrt(1.0/dim);
     for (k=dim, colp=normal; k--; )
       *colp++ = temp;
   }else {
     if (!toporient)
       norm= -norm;
     for (k=dim, colp=normal; k--; colp++) { /* k used below */
       temp= qh_divzero(*colp, norm, qh MINdenom_1, &zerodiv);
       if (!zerodiv)
         *colp= temp;
       else {
         maxp= qh_maxabsval(normal, dim);
         temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
         for (k=dim, colp=normal; k--; colp++)
           *colp= 0.0;
         *maxp= temp;
         zzinc_(Znearlysingular);
         trace0((qh ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",
                norm, qh furthest_id));
         return;
       }
     }
   }
 } /* normalize */
 
 
 /*---------------------------------
 
   qh_projectpoint( point, facet, dist )
     project point onto a facet by dist
 
   returns:
     returns a new point
 
   notes:
     if dist= distplane(point,facet)
       this projects point to hyperplane
     assumes qh_memfree_() is valid for normal_size
 */
 pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist) {
   pointT *newpoint, *np, *normal;
   int normsize= qh normal_size;
   int k;
   void **freelistp; /* used !qh_NOmem */
 
   qh_memalloc_(normsize, freelistp, newpoint, pointT);
   np= newpoint;
   normal= facet->normal;
   for (k=qh hull_dim; k--; )
     *(np++)= *point++ - dist * *normal++;
   return(newpoint);
 } /* projectpoint */
 
 
 /*---------------------------------
 
   qh_setfacetplane( facet )
     sets the hyperplane for a facet
     if qh.RANDOMdist, joggles hyperplane
 
   notes:
     uses global buffers qh.gm_matrix and qh.gm_row
     overwrites facet->normal if already defined
     updates Wnewvertex if PRINTstatistics
     sets facet->upperdelaunay if upper envelope of Delaunay triangulation
 
   design:
     copy vertex coordinates to qh.gm_matrix/gm_row
     compute determinate
     if nearzero
       recompute determinate with gaussian elimination
       if nearzero
         force outside orientation by testing interior point
 */
 void qh_setfacetplane(facetT *facet) {
   pointT *point;
   vertexT *vertex, **vertexp;
   int normsize= qh normal_size;
   int k,i, oldtrace= 0;
   realT dist;
   void **freelistp; /* used !qh_NOmem */
   coordT *coord, *gmcoord;
   pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
   boolT nearzero= False;
 
   zzinc_(Zsetplane);
   if (!facet->normal)
     qh_memalloc_(normsize, freelistp, facet->normal, coordT);
   if (facet == qh tracefacet) {
     oldtrace= qh IStracing;
     qh IStracing= 5;
     qh_fprintf(qh ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);
     qh_fprintf(qh ferr, 8013, "  Last point added to hull was p%d.", qh furthest_id);
     if (zzval_(Ztotmerge))
       qh_fprintf(qh ferr, 8014, "  Last merge was #%d.", zzval_(Ztotmerge));
     qh_fprintf(qh ferr, 8015, "\n\nCurrent summary is:\n");
       qh_printsummary(qh ferr);
   }
   if (qh hull_dim <= 4) {
     i= 0;
     if (qh RANDOMdist) {
       gmcoord= qh gm_matrix;
       FOREACHvertex_(facet->vertices) {
         qh gm_row[i++]= gmcoord;
         coord= vertex->point;
         for (k=qh hull_dim; k--; )
           *(gmcoord++)= *coord++ * qh_randomfactor(qh RANDOMa, qh RANDOMb);
       }
     }else {
       FOREACHvertex_(facet->vertices)
        qh gm_row[i++]= vertex->point;
     }
     qh_sethyperplane_det(qh hull_dim, qh gm_row, point0, facet->toporient,
                 facet->normal, &facet->offset, &nearzero);
   }
   if (qh hull_dim > 4 || nearzero) {
     i= 0;
     gmcoord= qh gm_matrix;
     FOREACHvertex_(facet->vertices) {
       if (vertex->point != point0) {
         qh gm_row[i++]= gmcoord;
         coord= vertex->point;
         point= point0;
         for (k=qh hull_dim; k--; )
           *(gmcoord++)= *coord++ - *point++;
       }
     }
     qh gm_row[i]= gmcoord;  /* for areasimplex */
     if (qh RANDOMdist) {
       gmcoord= qh gm_matrix;
       for (i=qh hull_dim-1; i--; ) {
         for (k=qh hull_dim; k--; )
           *(gmcoord++) *= qh_randomfactor(qh RANDOMa, qh RANDOMb);
       }
     }
     qh_sethyperplane_gauss(qh hull_dim, qh gm_row, point0, facet->toporient,
                 facet->normal, &facet->offset, &nearzero);
     if (nearzero) {
       if (qh_orientoutside(facet)) {
         trace0((qh ferr, 2, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh furthest_id));
       /* this is part of using Gaussian Elimination.  For example in 5-d
            1 1 1 1 0
            1 1 1 1 1
            0 0 0 1 0
            0 1 0 0 0
            1 0 0 0 0
            norm= 0.38 0.38 -0.76 0.38 0
          has a determinate of 1, but g.e. after subtracting pt. 0 has
          0's in the diagonal, even with full pivoting.  It does work
          if you subtract pt. 4 instead. */
       }
     }
   }
   facet->upperdelaunay= False;
   if (qh DELAUNAY) {
     if (qh UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
       if (facet->normal[qh hull_dim -1] >= qh ANGLEround * qh_ZEROdelaunay)
         facet->upperdelaunay= True;
     }else {
       if (facet->normal[qh hull_dim -1] > -qh ANGLEround * qh_ZEROdelaunay)
         facet->upperdelaunay= True;
     }
   }
   if (qh PRINTstatistics || qh IStracing || qh TRACElevel || qh JOGGLEmax < REALmax) {
     qh old_randomdist= qh RANDOMdist;
     qh RANDOMdist= False;
     FOREACHvertex_(facet->vertices) {
       if (vertex->point != point0) {
         boolT istrace= False;
         zinc_(Zdiststat);
         qh_distplane(vertex->point, facet, &dist);
         dist= fabs_(dist);
         zinc_(Znewvertex);
         wadd_(Wnewvertex, dist);
         if (dist > wwval_(Wnewvertexmax)) {
           wwval_(Wnewvertexmax)= dist;
           if (dist > qh max_outside) {
             qh max_outside= dist;  /* used by qh_maxouter() */
             if (dist > qh TRACEdist)
               istrace= True;
           }
         }else if (-dist > qh TRACEdist)
           istrace= True;
         if (istrace) {
           qh_fprintf(qh ferr, 8016, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
                 qh_pointid(vertex->point), vertex->id, dist, facet->id, qh furthest_id);
           qh_errprint("DISTANT", facet, NULL, NULL, NULL);
         }
       }
     }
     qh RANDOMdist= qh old_randomdist;
   }
   if (qh IStracing >= 3) {
     qh_fprintf(qh ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",
              facet->id, facet->offset);
     for (k=0; k < qh hull_dim; k++)
       qh_fprintf(qh ferr, 8018, "%2.2g ", facet->normal[k]);
     qh_fprintf(qh ferr, 8019, "\n");
   }
   if (facet == qh tracefacet)
     qh IStracing= oldtrace;
 } /* setfacetplane */
 
 
 /*---------------------------------
 
   qh_sethyperplane_det( dim, rows, point0, toporient, normal, offset, nearzero )
     given dim X dim array indexed by rows[], one row per point,
         toporient(flips all signs),
         and point0 (any row)
     set normalized hyperplane equation from oriented simplex
 
   returns:
     normal (normalized)
     offset (places point0 on the hyperplane)
     sets nearzero if hyperplane not through points
 
   notes:
     only defined for dim == 2..4
     rows[] is not modified
     solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
     see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
 
   derivation of 3-d minnorm
     Goal: all vertices V_i within qh.one_merge of hyperplane
     Plan: exactly translate the facet so that V_0 is the origin
           exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
           exactly rotate the effective perturbation to only effect n_0
              this introduces a factor of sqrt(3)
     n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
     Let M_d be the max coordinate difference
     Let M_a be the greater of M_d and the max abs. coordinate
     Let u be machine roundoff and distround be max error for distance computation
     The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
     The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
     Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
     Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d
 
   derivation of 4-d minnorm
     same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
      [if two vertices fixed on x-axis, can rotate the other two in yzw.]
     n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
      [all other terms contain at least two factors nearly zero.]
     The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
     Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
     Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
 */
 void qh_sethyperplane_det(int dim, coordT **rows, coordT *point0,
           boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
   realT maxround, dist;
   int i;
   pointT *point;
 
 
   if (dim == 2) {
     normal[0]= dY(1,0);
     normal[1]= dX(0,1);
     qh_normalize2(normal, dim, toporient, NULL, NULL);
     *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
     *nearzero= False;  /* since nearzero norm => incident points */
   }else if (dim == 3) {
     normal[0]= det2_(dY(2,0), dZ(2,0),
                      dY(1,0), dZ(1,0));
     normal[1]= det2_(dX(1,0), dZ(1,0),
                      dX(2,0), dZ(2,0));
     normal[2]= det2_(dX(2,0), dY(2,0),
                      dX(1,0), dY(1,0));
     qh_normalize2(normal, dim, toporient, NULL, NULL);
     *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
                + point0[2]*normal[2]);
     maxround= qh DISTround;
     for (i=dim; i--; ) {
       point= rows[i];
       if (point != point0) {
         dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
                + point[2]*normal[2]);
         if (dist > maxround || dist < -maxround) {
           *nearzero= True;
           break;
         }
       }
     }
   }else if (dim == 4) {
     normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
                         dY(1,0), dZ(1,0), dW(1,0),
                         dY(3,0), dZ(3,0), dW(3,0));
     normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
                         dX(1,0), dZ(1,0), dW(1,0),
                         dX(3,0), dZ(3,0), dW(3,0));
     normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
                         dX(1,0), dY(1,0), dW(1,0),
                         dX(3,0), dY(3,0), dW(3,0));
     normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
                         dX(1,0), dY(1,0), dZ(1,0),
                         dX(3,0), dY(3,0), dZ(3,0));
     qh_normalize2(normal, dim, toporient, NULL, NULL);
     *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
                + point0[2]*normal[2] + point0[3]*normal[3]);
     maxround= qh DISTround;
     for (i=dim; i--; ) {
       point= rows[i];
       if (point != point0) {
         dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
                + point[2]*normal[2] + point[3]*normal[3]);
         if (dist > maxround || dist < -maxround) {
           *nearzero= True;
           break;
         }
       }
     }
   }
   if (*nearzero) {
     zzinc_(Zminnorm);
     trace0((qh ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh furthest_id));
     zzinc_(Znearlysingular);
   }
 } /* sethyperplane_det */
 
 
 /*---------------------------------
 
   qh_sethyperplane_gauss( dim, rows, point0, toporient, normal, offset, nearzero )
     given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
     set normalized hyperplane equation from oriented simplex
 
   returns:
     normal (normalized)
     offset (places point0 on the hyperplane)
 
   notes:
     if nearzero
       orientation may be incorrect because of incorrect sign flips in gausselim
     solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
         or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
     i.e., N is normal to the hyperplane, and the unnormalized
         distance to [0 .. 1] is either 1 or   0
 
   design:
     perform gaussian elimination
     flip sign for negative values
     perform back substitution
     normalize result
     compute offset
 */
 void qh_sethyperplane_gauss(int dim, coordT **rows, pointT *point0,
                 boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
   coordT *pointcoord, *normalcoef;
   int k;
   boolT sign= toporient, nearzero2= False;
 
   qh_gausselim(rows, dim-1, dim, &sign, nearzero);
   for (k=dim-1; k--; ) {
     if ((rows[k])[k] < 0)
       sign ^= 1;
   }
   if (*nearzero) {
     zzinc_(Znearlysingular);
     trace0((qh ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh furthest_id));
     qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
   }else {
     qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
     if (nearzero2) {
       zzinc_(Znearlysingular);
       trace0((qh ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh furthest_id));
     }
   }
   if (nearzero2)
     *nearzero= True;
   qh_normalize2(normal, dim, True, NULL, NULL);
   pointcoord= point0;
   normalcoef= normal;
   *offset= -(*pointcoord++ * *normalcoef++);
   for (k=dim-1; k--; )
     *offset -= *pointcoord++ * *normalcoef++;
 } /* sethyperplane_gauss */
 
 
 
diff --git a/src/libqhull/geom.h b/src/libqhull/geom.h
index a418168..cfc735f 100644
--- a/src/libqhull/geom.h
+++ b/src/libqhull/geom.h
@@ -1,176 +1,176 @@
 /*
  ---------------------------------
 
   geom.h
     header file for geometric routines
 
    see qh-geom.htm and geom.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/geom.h#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/geom.h#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFgeom
 #define qhDEFgeom 1
 
 #include "libqhull.h"
 
 /* ============ -macros- ======================== */
 
 /*----------------------------------
 
   fabs_(a)
     returns the absolute value of a
 */
 #define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
 
 /*----------------------------------
 
   fmax_(a,b)
     returns the maximum value of a and b
 */
 #define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
 
 /*----------------------------------
 
   fmin_(a,b)
     returns the minimum value of a and b
 */
 #define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
 
 /*----------------------------------
 
   maximize_(maxval, val)
     set maxval to val if val is greater than maxval
 */
 #define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); }
 
 /*----------------------------------
 
   minimize_(minval, val)
     set minval to val if val is less than minval
 */
 #define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); }
 
 /*----------------------------------
 
   det2_(a1, a2,
         b1, b2)
 
     compute a 2-d determinate
 */
 #define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
 
 /*----------------------------------
 
   det3_(a1, a2, a3,
        b1, b2, b3,
        c1, c2, c3)
 
     compute a 3-d determinate
 */
 #define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
                 - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
 
 /*----------------------------------
 
   dX( p1, p2 )
   dY( p1, p2 )
   dZ( p1, p2 )
 
     given two indices into rows[],
 
     compute the difference between X, Y, or Z coordinates
 */
 #define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
 #define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
 #define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
 #define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
 
 /*============= prototypes in alphabetical order, infrequent at end ======= */
 
 void    qh_backnormal(realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
 void    qh_distplane(pointT *point, facetT *facet, realT *dist);
 facetT *qh_findbest(pointT *point, facetT *startfacet,
                      boolT bestoutside, boolT isnewfacets, boolT noupper,
                      realT *dist, boolT *isoutside, int *numpart);
 facetT *qh_findbesthorizon(boolT ischeckmax, pointT *point,
                      facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
 facetT *qh_findbestnew(pointT *point, facetT *startfacet, realT *dist,
                      boolT bestoutside, boolT *isoutside, int *numpart);
 void    qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
 realT   qh_getangle(pointT *vect1, pointT *vect2);
 pointT *qh_getcenter(setT *vertices);
 pointT *qh_getcentrum(facetT *facet);
 realT   qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
 void    qh_normalize(coordT *normal, int dim, boolT toporient);
 void    qh_normalize2(coordT *normal, int dim, boolT toporient,
             realT *minnorm, boolT *ismin);
 pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist);
 
 void    qh_setfacetplane(facetT *newfacets);
 void    qh_sethyperplane_det(int dim, coordT **rows, coordT *point0,
               boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
 void    qh_sethyperplane_gauss(int dim, coordT **rows, pointT *point0,
              boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
 boolT   qh_sharpnewfacets(void);
 
 /*========= infrequently used code in geom2.c =============*/
 
 coordT *qh_copypoints(coordT *points, int numpoints, int dimension);
 void    qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
 realT   qh_determinant(realT **rows, int dim, boolT *nearzero);
 realT   qh_detjoggle(pointT *points, int numpoints, int dimension);
 void    qh_detroundoff(void);
 realT   qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero);
 realT   qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp);
 realT   qh_distround(int dimension, realT maxabs, realT maxsumabs);
 realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
 realT   qh_facetarea(facetT *facet);
 realT   qh_facetarea_simplex(int dim, coordT *apex, setT *vertices,
           vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
 pointT *qh_facetcenter(setT *vertices);
 facetT *qh_findgooddist(pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
 void    qh_getarea(facetT *facetlist);
 boolT   qh_gram_schmidt(int dim, realT **rows);
 boolT   qh_inthresholds(coordT *normal, realT *angle);
 void    qh_joggleinput(void);
 realT  *qh_maxabsval(realT *normal, int dim);
 setT   *qh_maxmin(pointT *points, int numpoints, int dimension);
 realT   qh_maxouter(void);
 void    qh_maxsimplex(int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
 realT   qh_minabsval(realT *normal, int dim);
 int     qh_mindiff(realT *vecA, realT *vecB, int dim);
 boolT   qh_orientoutside(facetT *facet);
 void    qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane);
 coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
 void    qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol);
 void    qh_printpoints(FILE *fp, const char *string, setT *points);
 void    qh_projectinput(void);
 void    qh_projectpoints(signed char *project, int n, realT *points,
              int numpoints, int dim, realT *newpoints, int newdim);
 void    qh_rotateinput(realT **rows);
 void    qh_rotatepoints(realT *points, int numpoints, int dim, realT **rows);
 void    qh_scaleinput(void);
 void    qh_scalelast(coordT *points, int numpoints, int dim, coordT low,
                    coordT high, coordT newhigh);
 void    qh_scalepoints(pointT *points, int numpoints, int dim,
                 realT *newlows, realT *newhighs);
 boolT   qh_sethalfspace(int dim, coordT *coords, coordT **nextp,
               coordT *normal, coordT *offset, coordT *feasible);
 coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible);
 pointT *qh_voronoi_center(int dim, setT *points);
 
 #endif /* qhDEFgeom */
 
 
 
diff --git a/src/libqhull/geom2.c b/src/libqhull/geom2.c
index 251b681..260699e 100644
--- a/src/libqhull/geom2.c
+++ b/src/libqhull/geom2.c
@@ -1,2081 +1,2081 @@
 /*
  ---------------------------------
 
 
    geom2.c
    infrequently used geometric routines of qhull
 
    see qh-geom.htm and geom.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/geom2.c#3 $$Change: 1464 $
-   $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/geom2.c#5 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    frequently used code goes into geom.c
 */
 
 #include "qhull_a.h"
 
 /*================== functions in alphabetic order ============*/
 
 /*---------------------------------
 
   qh_copypoints( points, numpoints, dimension)
     return qh_malloc'd copy of points
 */
 coordT *qh_copypoints(coordT *points, int numpoints, int dimension) {
   int size;
   coordT *newpoints;
 
   size= numpoints * dimension * (int)sizeof(coordT);
   if (!(newpoints=(coordT*)qh_malloc((size_t)size))) {
     qh_fprintf(qh ferr, 6004, "qhull error: insufficient memory to copy %d points\n",
         numpoints);
     qh_errexit(qh_ERRmem, NULL, NULL);
   }
   memcpy((char *)newpoints, (char *)points, (size_t)size);
   return newpoints;
 } /* copypoints */
 
 /*---------------------------------
 
   qh_crossproduct( dim, vecA, vecB, vecC )
     crossproduct of 2 dim vectors
     C= A x B
 
   notes:
     from Glasner, Graphics Gems I, p. 639
     only defined for dim==3
 */
 void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
 
   if (dim == 3) {
     vecC[0]=   det2_(vecA[1], vecA[2],
                      vecB[1], vecB[2]);
     vecC[1]= - det2_(vecA[0], vecA[2],
                      vecB[0], vecB[2]);
     vecC[2]=   det2_(vecA[0], vecA[1],
                      vecB[0], vecB[1]);
   }
 } /* vcross */
 
 /*---------------------------------
 
   qh_determinant( rows, dim, nearzero )
     compute signed determinant of a square matrix
     uses qh.NEARzero to test for degenerate matrices
 
   returns:
     determinant
     overwrites rows and the matrix
     if dim == 2 or 3
       nearzero iff determinant < qh NEARzero[dim-1]
       (!quite correct, not critical)
     if dim >= 4
       nearzero iff diagonal[k] < qh NEARzero[k]
 */
 realT qh_determinant(realT **rows, int dim, boolT *nearzero) {
   realT det=0;
   int i;
   boolT sign= False;
 
   *nearzero= False;
   if (dim < 2) {
     qh_fprintf(qh ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }else if (dim == 2) {
     det= det2_(rows[0][0], rows[0][1],
                  rows[1][0], rows[1][1]);
     if (fabs_(det) < qh NEARzero[1])  /* not really correct, what should this be? */
       *nearzero= True;
   }else if (dim == 3) {
     det= det3_(rows[0][0], rows[0][1], rows[0][2],
                  rows[1][0], rows[1][1], rows[1][2],
                  rows[2][0], rows[2][1], rows[2][2]);
     if (fabs_(det) < qh NEARzero[2])  /* not really correct, what should this be? */
       *nearzero= True;
   }else {
     qh_gausselim(rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok*/
     det= 1.0;
     for (i=dim; i--; )
       det *= (rows[i])[i];
     if (sign)
       det= -det;
   }
   return det;
 } /* determinant */
 
 /*---------------------------------
 
   qh_detjoggle( points, numpoints, dimension )
     determine default max joggle for point array
       as qh_distround * qh_JOGGLEdefault
 
   returns:
     initial value for JOGGLEmax from points and REALepsilon
 
   notes:
     computes DISTround since qh_maxmin not called yet
     if qh SCALElast, last dimension will be scaled later to MAXwidth
 
     loop duplicated from qh_maxmin
 */
 realT qh_detjoggle(pointT *points, int numpoints, int dimension) {
   realT abscoord, distround, joggle, maxcoord, mincoord;
   pointT *point, *pointtemp;
   realT maxabs= -REALmax;
   realT sumabs= 0;
   realT maxwidth= 0;
   int k;
 
   for (k=0; k < dimension; k++) {
     if (qh SCALElast && k == dimension-1)
       abscoord= maxwidth;
     else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
       abscoord= 2 * maxabs * maxabs;  /* may be low by qh hull_dim/2 */
     else {
       maxcoord= -REALmax;
       mincoord= REALmax;
       FORALLpoint_(points, numpoints) {
         maximize_(maxcoord, point[k]);
         minimize_(mincoord, point[k]);
       }
       maximize_(maxwidth, maxcoord-mincoord);
       abscoord= fmax_(maxcoord, -mincoord);
     }
     sumabs += abscoord;
     maximize_(maxabs, abscoord);
   } /* for k */
   distround= qh_distround(qh hull_dim, maxabs, sumabs);
   joggle= distround * qh_JOGGLEdefault;
   maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
   trace2((qh ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
   return joggle;
 } /* detjoggle */
 
 /*---------------------------------
 
   qh_detroundoff()
     determine maximum roundoff errors from
       REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,
       qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
 
     accounts for qh.SETroundoff, qh.RANDOMdist, qh MERGEexact
       qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
       qh.postmerge_centrum, qh.MINoutside,
       qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
 
   returns:
     sets qh.DISTround, etc. (see below)
     appends precision constants to qh.qhull_options
 
   see:
     qh_maxmin() for qh.NEARzero
 
   design:
     determine qh.DISTround for distance computations
     determine minimum denominators for qh_divzero
     determine qh.ANGLEround for angle computations
     adjust qh.premerge_cos,... for roundoff error
     determine qh.ONEmerge for maximum error due to a single merge
     determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
       qh.MINoutside, qh.WIDEfacet
     initialize qh.max_vertex and qh.minvertex
 */
 void qh_detroundoff(void) {
 
   qh_option("_max-width", NULL, &qh MAXwidth);
   if (!qh SETroundoff) {
     qh DISTround= qh_distround(qh hull_dim, qh MAXabs_coord, qh MAXsumcoord);
     if (qh RANDOMdist)
       qh DISTround += qh RANDOMfactor * qh MAXabs_coord;
     qh_option("Error-roundoff", NULL, &qh DISTround);
   }
   qh MINdenom= qh MINdenom_1 * qh MAXabs_coord;
   qh MINdenom_1_2= sqrt(qh MINdenom_1 * qh hull_dim) ;  /* if will be normalized */
   qh MINdenom_2= qh MINdenom_1_2 * qh MAXabs_coord;
                                               /* for inner product */
   qh ANGLEround= 1.01 * qh hull_dim * REALepsilon;
   if (qh RANDOMdist)
     qh ANGLEround += qh RANDOMfactor;
   if (qh premerge_cos < REALmax/2) {
     qh premerge_cos -= qh ANGLEround;
     if (qh RANDOMdist)
       qh_option("Angle-premerge-with-random", NULL, &qh premerge_cos);
   }
   if (qh postmerge_cos < REALmax/2) {
     qh postmerge_cos -= qh ANGLEround;
     if (qh RANDOMdist)
       qh_option("Angle-postmerge-with-random", NULL, &qh postmerge_cos);
   }
   qh premerge_centrum += 2 * qh DISTround;    /*2 for centrum and distplane()*/
   qh postmerge_centrum += 2 * qh DISTround;
   if (qh RANDOMdist && (qh MERGEexact || qh PREmerge))
     qh_option("Centrum-premerge-with-random", NULL, &qh premerge_centrum);
   if (qh RANDOMdist && qh POSTmerge)
     qh_option("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum);
   { /* compute ONEmerge, max vertex offset for merging simplicial facets */
     realT maxangle= 1.0, maxrho;
 
     minimize_(maxangle, qh premerge_cos);
     minimize_(maxangle, qh postmerge_cos);
     /* max diameter * sin theta + DISTround for vertex to its hyperplane */
     qh ONEmerge= sqrt((realT)qh hull_dim) * qh MAXwidth *
       sqrt(1.0 - maxangle * maxangle) + qh DISTround;
     maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
     maximize_(qh ONEmerge, maxrho);
     maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
     maximize_(qh ONEmerge, maxrho);
     if (qh MERGING)
       qh_option("_one-merge", NULL, &qh ONEmerge);
   }
   qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */
   if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) {
     realT maxdist;             /* adjust qh.NEARinside for joggle */
     qh KEEPnearinside= True;
     maxdist= sqrt((realT)qh hull_dim) * qh JOGGLEmax + qh DISTround;
     maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
     maximize_(qh NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
   }
   if (qh KEEPnearinside)
     qh_option("_near-inside", NULL, &qh NEARinside);
   if (qh JOGGLEmax < qh DISTround) {
     qh_fprintf(qh ferr, 6006, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
          qh JOGGLEmax, qh DISTround);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (qh MINvisible > REALmax/2) {
     if (!qh MERGING)
       qh MINvisible= qh DISTround;
     else if (qh hull_dim <= 3)
       qh MINvisible= qh premerge_centrum;
     else
       qh MINvisible= qh_COPLANARratio * qh premerge_centrum;
     if (qh APPROXhull && qh MINvisible > qh MINoutside)
       qh MINvisible= qh MINoutside;
     qh_option("Visible-distance", NULL, &qh MINvisible);
   }
   if (qh MAXcoplanar > REALmax/2) {
     qh MAXcoplanar= qh MINvisible;
     qh_option("U-coplanar-distance", NULL, &qh MAXcoplanar);
   }
   if (!qh APPROXhull) {             /* user may specify qh MINoutside */
     qh MINoutside= 2 * qh MINvisible;
     if (qh premerge_cos < REALmax/2)
       maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord);
     qh_option("Width-outside", NULL, &qh MINoutside);
   }
   qh WIDEfacet= qh MINoutside;
   maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar);
   maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible);
   qh_option("_wide-facet", NULL, &qh WIDEfacet);
   if (qh MINvisible > qh MINoutside + 3 * REALepsilon
   && !qh BESToutside && !qh FORCEoutput)
     qh_fprintf(qh ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
              qh MINvisible, qh MINoutside);
   qh max_vertex= qh DISTround;
   qh min_vertex= -qh DISTround;
   /* numeric constants reported in printsummary */
 } /* detroundoff */
 
 /*---------------------------------
 
   qh_detsimplex( apex, points, dim, nearzero )
     compute determinant of a simplex with point apex and base points
 
   returns:
      signed determinant and nearzero from qh_determinant
 
   notes:
      uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
 
   design:
     construct qm_matrix by subtracting apex from points
     compute determinate
 */
 realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
   pointT *coorda, *coordp, *gmcoord, *point, **pointp;
   coordT **rows;
   int k,  i=0;
   realT det;
 
   zinc_(Zdetsimplex);
   gmcoord= qh gm_matrix;
   rows= qh gm_row;
   FOREACHpoint_(points) {
     if (i == dim)
       break;
     rows[i++]= gmcoord;
     coordp= point;
     coorda= apex;
     for (k=dim; k--; )
       *(gmcoord++)= *coordp++ - *coorda++;
   }
   if (i < dim) {
     qh_fprintf(qh ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
                i, dim);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   det= qh_determinant(rows, dim, nearzero);
   trace2((qh ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
           det, qh_pointid(apex), dim, *nearzero));
   return det;
 } /* detsimplex */
 
 /*---------------------------------
 
   qh_distnorm( dim, point, normal, offset )
     return distance from point to hyperplane at normal/offset
 
   returns:
     dist
 
   notes:
     dist > 0 if point is outside of hyperplane
 
   see:
     qh_distplane in geom.c
 */
 realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) {
   coordT *normalp= normal, *coordp= point;
   realT dist;
   int k;
 
   dist= *offsetp;
   for (k=dim; k--; )
     dist += *(coordp++) * *(normalp++);
   return dist;
 } /* distnorm */
 
 /*---------------------------------
 
   qh_distround(dimension, maxabs, maxsumabs )
     compute maximum round-off error for a distance computation
       to a normalized hyperplane
     maxabs is the maximum absolute value of a coordinate
     maxsumabs is the maximum possible sum of absolute coordinate values
 
   returns:
     max dist round for REALepsilon
 
   notes:
     calculate roundoff error according to
     Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
     use sqrt(dim) since one vector is normalized
       or use maxsumabs since one vector is < 1
 */
 realT qh_distround(int dimension, realT maxabs, realT maxsumabs) {
   realT maxdistsum, maxround;
 
   maxdistsum= sqrt((realT)dimension) * maxabs;
   minimize_( maxdistsum, maxsumabs);
   maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
               /* adds maxabs for offset */
   trace4((qh ferr, 4008, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",
                  maxround, maxabs, maxsumabs, maxdistsum));
   return maxround;
 } /* distround */
 
 /*---------------------------------
 
   qh_divzero( numer, denom, mindenom1, zerodiv )
     divide by a number that's nearly zero
     mindenom1= minimum denominator for dividing into 1.0
 
   returns:
     quotient
     sets zerodiv and returns 0.0 if it would overflow
 
   design:
     if numer is nearly zero and abs(numer) < abs(denom)
       return numer/denom
     else if numer is nearly zero
       return 0 and zerodiv
     else if denom/numer non-zero
       return numer/denom
     else
       return 0 and zerodiv
 */
 realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
   realT temp, numerx, denomx;
 
 
   if (numer < mindenom1 && numer > -mindenom1) {
     numerx= fabs_(numer);
     denomx= fabs_(denom);
     if (numerx < denomx) {
       *zerodiv= False;
       return numer/denom;
     }else {
       *zerodiv= True;
       return 0.0;
     }
   }
   temp= denom/numer;
   if (temp > mindenom1 || temp < -mindenom1) {
     *zerodiv= False;
     return numer/denom;
   }else {
     *zerodiv= True;
     return 0.0;
   }
 } /* divzero */
 
 
 /*---------------------------------
 
   qh_facetarea( facet )
     return area for a facet
 
   notes:
     if non-simplicial,
       uses centrum to triangulate facet and sums the projected areas.
     if (qh DELAUNAY),
       computes projected area instead for last coordinate
     assumes facet->normal exists
     projecting tricoplanar facets to the hyperplane does not appear to make a difference
 
   design:
     if simplicial
       compute area
     else
       for each ridge
         compute area from centrum to ridge
     negate area if upper Delaunay facet
 */
 realT qh_facetarea(facetT *facet) {
   vertexT *apex;
   pointT *centrum;
   realT area= 0.0;
   ridgeT *ridge, **ridgep;
 
   if (facet->simplicial) {
     apex= SETfirstt_(facet->vertices, vertexT);
     area= qh_facetarea_simplex(qh hull_dim, apex->point, facet->vertices,
                     apex, facet->toporient, facet->normal, &facet->offset);
   }else {
     if (qh CENTERtype == qh_AScentrum)
       centrum= facet->center;
     else
       centrum= qh_getcentrum(facet);
     FOREACHridge_(facet->ridges)
       area += qh_facetarea_simplex(qh hull_dim, centrum, ridge->vertices,
                  NULL, (boolT)(ridge->top == facet),  facet->normal, &facet->offset);
     if (qh CENTERtype != qh_AScentrum)
       qh_memfree(centrum, qh normal_size);
   }
   if (facet->upperdelaunay && qh DELAUNAY)
     area= -area;  /* the normal should be [0,...,1] */
   trace4((qh ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
   return area;
 } /* facetarea */
 
 /*---------------------------------
 
   qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset )
     return area for a simplex defined by
       an apex, a base of vertices, an orientation, and a unit normal
     if simplicial or tricoplanar facet,
       notvertex is defined and it is skipped in vertices
 
   returns:
     computes area of simplex projected to plane [normal,offset]
     returns 0 if vertex too far below plane (qh WIDEfacet)
       vertex can't be apex of tricoplanar facet
 
   notes:
     if (qh DELAUNAY),
       computes projected area instead for last coordinate
     uses qh gm_matrix/gm_row and qh hull_dim
     helper function for qh_facetarea
 
   design:
     if Notvertex
       translate simplex to apex
     else
       project simplex to normal/offset
       translate simplex to apex
     if Delaunay
       set last row/column to 0 with -1 on diagonal
     else
       set last row to Normal
     compute determinate
     scale and flip sign for area
 */
 realT qh_facetarea_simplex(int dim, coordT *apex, setT *vertices,
         vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
   pointT *coorda, *coordp, *gmcoord;
   coordT **rows, *normalp;
   int k,  i=0;
   realT area, dist;
   vertexT *vertex, **vertexp;
   boolT nearzero;
 
   gmcoord= qh gm_matrix;
   rows= qh gm_row;
   FOREACHvertex_(vertices) {
     if (vertex == notvertex)
       continue;
     rows[i++]= gmcoord;
     coorda= apex;
     coordp= vertex->point;
     normalp= normal;
     if (notvertex) {
       for (k=dim; k--; )
         *(gmcoord++)= *coordp++ - *coorda++;
     }else {
       dist= *offset;
       for (k=dim; k--; )
         dist += *coordp++ * *normalp++;
       if (dist < -qh WIDEfacet) {
         zinc_(Znoarea);
         return 0.0;
       }
       coordp= vertex->point;
       normalp= normal;
       for (k=dim; k--; )
         *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
     }
   }
   if (i != dim-1) {
     qh_fprintf(qh ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
                i, dim);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   rows[i]= gmcoord;
   if (qh DELAUNAY) {
     for (i=0; i < dim-1; i++)
       rows[i][dim-1]= 0.0;
     for (k=dim; k--; )
       *(gmcoord++)= 0.0;
     rows[dim-1][dim-1]= -1.0;
   }else {
     normalp= normal;
     for (k=dim; k--; )
       *(gmcoord++)= *normalp++;
   }
   zinc_(Zdetsimplex);
   area= qh_determinant(rows, dim, &nearzero);
   if (toporient)
     area= -area;
   area *= qh AREAfactor;
   trace4((qh ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
           area, qh_pointid(apex), toporient, nearzero));
   return area;
 } /* facetarea_simplex */
 
 /*---------------------------------
 
   qh_facetcenter( vertices )
     return Voronoi center (Voronoi vertex) for a facet's vertices
 
   returns:
     return temporary point equal to the center
 
   see:
     qh_voronoi_center()
 */
 pointT *qh_facetcenter(setT *vertices) {
   setT *points= qh_settemp(qh_setsize(vertices));
   vertexT *vertex, **vertexp;
   pointT *center;
 
   FOREACHvertex_(vertices)
     qh_setappend(&points, vertex->point);
   center= qh_voronoi_center(qh hull_dim-1, points);
   qh_settempfree(&points);
   return center;
 } /* facetcenter */
 
 /*---------------------------------
 
   qh_findgooddist( point, facetA, dist, facetlist )
     find best good facet visible for point from facetA
     assumes facetA is visible from point
 
   returns:
     best facet, i.e., good facet that is furthest from point
       distance to best facet
       NULL if none
 
     moves good, visible facets (and some other visible facets)
       to end of qh facet_list
 
   notes:
     uses qh visit_id
 
   design:
     initialize bestfacet if facetA is good
     move facetA to end of facetlist
     for each facet on facetlist
       for each unvisited neighbor of facet
         move visible neighbors to end of facetlist
         update best good neighbor
         if no good neighbors, update best facet
 */
 facetT *qh_findgooddist(pointT *point, facetT *facetA, realT *distp,
                facetT **facetlist) {
   realT bestdist= -REALmax, dist;
   facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
   boolT goodseen= False;
 
   if (facetA->good) {
     zzinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
     qh_distplane(point, facetA, &bestdist);
     bestfacet= facetA;
     goodseen= True;
   }
   qh_removefacet(facetA);
   qh_appendfacet(facetA);
   *facetlist= facetA;
   facetA->visitid= ++qh visit_id;
   FORALLfacet_(*facetlist) {
     FOREACHneighbor_(facet) {
       if (neighbor->visitid == qh visit_id)
         continue;
       neighbor->visitid= qh visit_id;
       if (goodseen && !neighbor->good)
         continue;
       zzinc_(Zcheckpart);
       qh_distplane(point, neighbor, &dist);
       if (dist > 0) {
         qh_removefacet(neighbor);
         qh_appendfacet(neighbor);
         if (neighbor->good) {
           goodseen= True;
           if (dist > bestdist) {
             bestdist= dist;
             bestfacet= neighbor;
           }
         }
       }
     }
   }
   if (bestfacet) {
     *distp= bestdist;
     trace2((qh ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
       qh_pointid(point), bestdist, bestfacet->id));
     return bestfacet;
   }
   trace4((qh ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",
       qh_pointid(point), facetA->id));
   return NULL;
 }  /* findgooddist */
 
 /*---------------------------------
 
   qh_getarea( facetlist )
     set area of all facets in facetlist
     collect statistics
     nop if hasAreaVolume
 
   returns:
     sets qh totarea/totvol to total area and volume of convex hull
     for Delaunay triangulation, computes projected area of the lower or upper hull
       ignores upper hull if qh ATinfinity
 
   notes:
     could compute outer volume by expanding facet area by rays from interior
     the following attempt at perpendicular projection underestimated badly:
       qh.totoutvol += (-dist + facet->maxoutside + qh DISTround)
                             * area/ qh hull_dim;
   design:
     for each facet on facetlist
       compute facet->area
       update qh.totarea and qh.totvol
 */
 void qh_getarea(facetT *facetlist) {
   realT area;
   realT dist;
   facetT *facet;
 
   if (qh hasAreaVolume)
     return;
   if (qh REPORTfreq)
     qh_fprintf(qh ferr, 8020, "computing area of each facet and volume of the convex hull\n");
   else
     trace1((qh ferr, 1001, "qh_getarea: computing volume and area for each facet\n"));
   qh totarea= qh totvol= 0.0;
   FORALLfacet_(facetlist) {
     if (!facet->normal)
       continue;
     if (facet->upperdelaunay && qh ATinfinity)
       continue;
     if (!facet->isarea) {
       facet->f.area= qh_facetarea(facet);
       facet->isarea= True;
     }
     area= facet->f.area;
     if (qh DELAUNAY) {
       if (facet->upperdelaunay == qh UPPERdelaunay)
         qh totarea += area;
     }else {
       qh totarea += area;
       qh_distplane(qh interior_point, facet, &dist);
       qh totvol += -dist * area/ qh hull_dim;
     }
     if (qh PRINTstatistics) {
       wadd_(Wareatot, area);
       wmax_(Wareamax, area);
       wmin_(Wareamin, area);
     }
   }
   qh hasAreaVolume= True;
 } /* getarea */
 
 /*---------------------------------
 
   qh_gram_schmidt( dim, row )
     implements Gram-Schmidt orthogonalization by rows
 
   returns:
     false if zero norm
     overwrites rows[dim][dim]
 
   notes:
     see Golub & van Loan Algorithm 6.2-2
     overflow due to small divisors not handled
 
   design:
     for each row
       compute norm for row
       if non-zero, normalize row
       for each remaining rowA
         compute inner product of row and rowA
         reduce rowA by row * inner product
 */
 boolT qh_gram_schmidt(int dim, realT **row) {
   realT *rowi, *rowj, norm;
   int i, j, k;
 
   for (i=0; i < dim; i++) {
     rowi= row[i];
     for (norm= 0.0, k= dim; k--; rowi++)
       norm += *rowi * *rowi;
     norm= sqrt(norm);
     wmin_(Wmindenom, norm);
     if (norm == 0.0)  /* either 0 or overflow due to sqrt */
       return False;
     for (k=dim; k--; )
       *(--rowi) /= norm;
     for (j=i+1; j < dim; j++) {
       rowj= row[j];
       for (norm= 0.0, k=dim; k--; )
         norm += *rowi++ * *rowj++;
       for (k=dim; k--; )
         *(--rowj) -= *(--rowi) * norm;
     }
   }
   return True;
 } /* gram_schmidt */
 
 
 /*---------------------------------
 
   qh_inthresholds( normal, angle )
     return True if normal within qh.lower_/upper_threshold
 
   returns:
     estimate of angle by summing of threshold diffs
       angle may be NULL
       smaller "angle" is better
 
   notes:
     invalid if qh.SPLITthresholds
 
   see:
     qh.lower_threshold in qh_initbuild()
     qh_initthresholds()
 
   design:
     for each dimension
       test threshold
 */
 boolT qh_inthresholds(coordT *normal, realT *angle) {
   boolT within= True;
   int k;
   realT threshold;
 
   if (angle)
     *angle= 0.0;
   for (k=0; k < qh hull_dim; k++) {
     threshold= qh lower_threshold[k];
     if (threshold > -REALmax/2) {
       if (normal[k] < threshold)
         within= False;
       if (angle) {
         threshold -= normal[k];
         *angle += fabs_(threshold);
       }
     }
     if (qh upper_threshold[k] < REALmax/2) {
       threshold= qh upper_threshold[k];
       if (normal[k] > threshold)
         within= False;
       if (angle) {
         threshold -= normal[k];
         *angle += fabs_(threshold);
       }
     }
   }
   return within;
 } /* inthresholds */
 
 
 /*---------------------------------
 
   qh_joggleinput()
     randomly joggle input to Qhull by qh.JOGGLEmax
     initial input is qh.first_point/qh.num_points of qh.hull_dim
       repeated calls use qh.input_points/qh.num_points
 
   returns:
     joggles points at qh.first_point/qh.num_points
     copies data to qh.input_points/qh.input_malloc if first time
     determines qh.JOGGLEmax if it was zero
     if qh.DELAUNAY
       computes the Delaunay projection of the joggled points
 
   notes:
     if qh.DELAUNAY, unnecessarily joggles the last coordinate
     the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
 
   design:
     if qh.DELAUNAY
       set qh.SCALElast for reduced precision errors
     if first call
       initialize qh.input_points to the original input points
       if qh.JOGGLEmax == 0
         determine default qh.JOGGLEmax
     else
       increase qh.JOGGLEmax according to qh.build_cnt
     joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
     if qh.DELAUNAY
       sets the Delaunay projection
 */
 void qh_joggleinput(void) {
   int i, seed, size;
   coordT *coordp, *inputp;
   realT randr, randa, randb;
 
   if (!qh input_points) { /* first call */
     qh input_points= qh first_point;
     qh input_malloc= qh POINTSmalloc;
     size= qh num_points * qh hull_dim * sizeof(coordT);
     if (!(qh first_point=(coordT*)qh_malloc((size_t)size))) {
       qh_fprintf(qh ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",
           qh num_points);
       qh_errexit(qh_ERRmem, NULL, NULL);
     }
     qh POINTSmalloc= True;
     if (qh JOGGLEmax == 0.0) {
       qh JOGGLEmax= qh_detjoggle(qh input_points, qh num_points, qh hull_dim);
       qh_option("QJoggle", NULL, &qh JOGGLEmax);
     }
   }else {                 /* repeated call */
     if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) {
       if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
         realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease;
         if (qh JOGGLEmax < maxjoggle) {
           qh JOGGLEmax *= qh_JOGGLEincrease;
           minimize_(qh JOGGLEmax, maxjoggle);
         }
       }
     }
     qh_option("QJoggle", NULL, &qh JOGGLEmax);
   }
   if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) {
       qh_fprintf(qh ferr, 6010, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input.  If possible, recompile Qhull with higher-precision reals.\n",
                 qh JOGGLEmax);
       qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   /* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
   seed= qh_RANDOMint;
   qh_option("_joggle-seed", &seed, NULL);
   trace0((qh ferr, 6, "qh_joggleinput: joggle input by %2.2g with seed %d\n",
     qh JOGGLEmax, seed));
   inputp= qh input_points;
   coordp= qh first_point;
   randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax;
   randb= -qh JOGGLEmax;
   size= qh num_points * qh hull_dim;
   for (i=size; i--; ) {
     randr= qh_RANDOMint;
     *(coordp++)= *(inputp++) + (randr * randa + randb);
   }
   if (qh DELAUNAY) {
     qh last_low= qh last_high= qh last_newhigh= REALmax;
     qh_setdelaunay(qh hull_dim, qh num_points, qh first_point);
   }
 } /* joggleinput */
 
 /*---------------------------------
 
   qh_maxabsval( normal, dim )
     return pointer to maximum absolute value of a dim vector
     returns NULL if dim=0
 */
 realT *qh_maxabsval(realT *normal, int dim) {
   realT maxval= -REALmax;
   realT *maxp= NULL, *colp, absval;
   int k;
 
   for (k=dim, colp= normal; k--; colp++) {
     absval= fabs_(*colp);
     if (absval > maxval) {
       maxval= absval;
       maxp= colp;
     }
   }
   return maxp;
 } /* maxabsval */
 
 
 /*---------------------------------
 
   qh_maxmin( points, numpoints, dimension )
     return max/min points for each dimension
     determine max and min coordinates
 
   returns:
     returns a temporary set of max and min points
       may include duplicate points. Does not include qh.GOODpoint
     sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
          qh.MAXlastcoord, qh.MINlastcoord
     initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
 
   notes:
     loop duplicated in qh_detjoggle()
 
   design:
     initialize global precision variables
     checks definition of REAL...
     for each dimension
       for each point
         collect maximum and minimum point
       collect maximum of maximums and minimum of minimums
       determine qh.NEARzero for Gaussian Elimination
 */
 setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
   int k;
   realT maxcoord, temp;
   pointT *minimum, *maximum, *point, *pointtemp;
   setT *set;
 
   qh max_outside= 0.0;
   qh MAXabs_coord= 0.0;
   qh MAXwidth= -REALmax;
   qh MAXsumcoord= 0.0;
   qh min_vertex= 0.0;
   qh WAScoplanar= False;
   if (qh ZEROcentrum)
     qh ZEROall_ok= True;
   if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
   && REALmax > 0.0 && -REALmax < 0.0)
     ; /* all ok */
   else {
     qh_fprintf(qh ferr, 6011, "qhull error: floating point constants in user.h are wrong\n\
 REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",
              REALepsilon, REALmin, REALmax, -REALmax);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   set= qh_settemp(2*dimension);
   for (k=0; k < dimension; k++) {
     if (points == qh GOODpointp)
       minimum= maximum= points + dimension;
     else
       minimum= maximum= points;
     FORALLpoint_(points, numpoints) {
       if (point == qh GOODpointp)
         continue;
       if (maximum[k] < point[k])
         maximum= point;
       else if (minimum[k] > point[k])
         minimum= point;
     }
     if (k == dimension-1) {
       qh MINlastcoord= minimum[k];
       qh MAXlastcoord= maximum[k];
     }
     if (qh SCALElast && k == dimension-1)
       maxcoord= qh MAXwidth;
     else {
       maxcoord= fmax_(maximum[k], -minimum[k]);
       if (qh GOODpointp) {
         temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]);
         maximize_(maxcoord, temp);
       }
       temp= maximum[k] - minimum[k];
       maximize_(qh MAXwidth, temp);
     }
     maximize_(qh MAXabs_coord, maxcoord);
     qh MAXsumcoord += maxcoord;
     qh_setappend(&set, maximum);
     qh_setappend(&set, minimum);
     /* calculation of qh NEARzero is based on error formula 4.4-13 of
        Golub & van Loan, authors say n^3 can be ignored and 10 be used in
        place of rho */
     qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon;
   }
   if (qh IStracing >=1)
     qh_printpoints(qh ferr, "qh_maxmin: found the max and min points(by dim):", set);
   return(set);
 } /* maxmin */
 
 /*---------------------------------
 
   qh_maxouter()
     return maximum distance from facet to outer plane
     normally this is qh.max_outside+qh.DISTround
     does not include qh.JOGGLEmax
 
   see:
     qh_outerinner()
 
   notes:
     need to add another qh.DISTround if testing actual point with computation
 
   for joggle:
     qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
     need to use Wnewvertexmax since could have a coplanar point for a high
       facet that is replaced by a low facet
     need to add qh.JOGGLEmax if testing input points
 */
 realT qh_maxouter(void) {
   realT dist;
 
   dist= fmax_(qh max_outside, qh DISTround);
   dist += qh DISTround;
   trace4((qh ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh max_outside));
   return dist;
 } /* maxouter */
 
 /*---------------------------------
 
   qh_maxsimplex( dim, maxpoints, points, numpoints, simplex )
     determines maximum simplex for a set of points
     starts from points already in simplex
     skips qh.GOODpointp (assumes that it isn't in maxpoints)
 
   returns:
     simplex with dim+1 points
 
   notes:
     assumes at least pointsneeded points in points
     maximizes determinate for x,y,z,w, etc.
     uses maxpoints as long as determinate is clearly non-zero
 
   design:
     initialize simplex with at least two points
       (find points with max or min x coordinate)
     for each remaining dimension
       add point that maximizes the determinate
         (use points from maxpoints first)
 */
 void qh_maxsimplex(int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
   pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
   boolT nearzero, maxnearzero= False;
   int k, sizinit;
   realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
 
   sizinit= qh_setsize(*simplex);
   if (sizinit < 2) {
     if (qh_setsize(maxpoints) >= 2) {
       FOREACHpoint_(maxpoints) {
         if (maxcoord < point[0]) {
           maxcoord= point[0];
           maxx= point;
         }
         if (mincoord > point[0]) {
           mincoord= point[0];
           minx= point;
         }
       }
     }else {
       FORALLpoint_(points, numpoints) {
         if (point == qh GOODpointp)
           continue;
         if (maxcoord < point[0]) {
           maxcoord= point[0];
           maxx= point;
         }
         if (mincoord > point[0]) {
           mincoord= point[0];
           minx= point;
         }
       }
     }
     qh_setunique(simplex, minx);
     if (qh_setsize(*simplex) < 2)
       qh_setunique(simplex, maxx);
     sizinit= qh_setsize(*simplex);
     if (sizinit < 2) {
       qh_precision("input has same x coordinate");
       if (zzval_(Zsetplane) > qh hull_dim+1) {
         qh_fprintf(qh ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",
                  qh_setsize(maxpoints)+numpoints);
         qh_errexit(qh_ERRprec, NULL, NULL);
       }else {
         qh_fprintf(qh ferr, 6013, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh hull_dim);
         qh_errexit(qh_ERRinput, NULL, NULL);
       }
     }
   }
   for (k=sizinit; k < dim+1; k++) {
     maxpoint= NULL;
     maxdet= -REALmax;
     FOREACHpoint_(maxpoints) {
       if (!qh_setin(*simplex, point)) {
         det= qh_detsimplex(point, *simplex, k, &nearzero);
         if ((det= fabs_(det)) > maxdet) {
           maxdet= det;
           maxpoint= point;
           maxnearzero= nearzero;
         }
       }
     }
     if (!maxpoint || maxnearzero) {
       zinc_(Zsearchpoints);
       if (!maxpoint) {
         trace0((qh ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
       }else {
         trace0((qh ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",
                 k+1, qh_pointid(maxpoint), maxdet));
       }
       FORALLpoint_(points, numpoints) {
         if (point == qh GOODpointp)
           continue;
         if (!qh_setin(*simplex, point)) {
           det= qh_detsimplex(point, *simplex, k, &nearzero);
           if ((det= fabs_(det)) > maxdet) {
             maxdet= det;
             maxpoint= point;
             maxnearzero= nearzero;
           }
         }
       }
     } /* !maxpoint */
     if (!maxpoint) {
       qh_fprintf(qh ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");
       qh_errexit(qh_ERRqhull, NULL, NULL);
     }
     qh_setappend(simplex, maxpoint);
     trace1((qh ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
             qh_pointid(maxpoint), k+1, maxdet));
   } /* k */
 } /* maxsimplex */
 
 /*---------------------------------
 
   qh_minabsval( normal, dim )
     return minimum absolute value of a dim vector
 */
 realT qh_minabsval(realT *normal, int dim) {
   realT minval= 0;
   realT maxval= 0;
   realT *colp;
   int k;
 
   for (k=dim, colp=normal; k--; colp++) {
     maximize_(maxval, *colp);
     minimize_(minval, *colp);
   }
   return fmax_(maxval, -minval);
 } /* minabsval */
 
 
 /*---------------------------------
 
   qh_mindif( vecA, vecB, dim )
     return index of min abs. difference of two vectors
 */
 int qh_mindiff(realT *vecA, realT *vecB, int dim) {
   realT mindiff= REALmax, diff;
   realT *vecAp= vecA, *vecBp= vecB;
   int k, mink= 0;
 
   for (k=0; k < dim; k++) {
     diff= *vecAp++ - *vecBp++;
     diff= fabs_(diff);
     if (diff < mindiff) {
       mindiff= diff;
       mink= k;
     }
   }
   return mink;
 } /* mindiff */
 
 
 
 /*---------------------------------
 
   qh_orientoutside( facet  )
     make facet outside oriented via qh.interior_point
 
   returns:
     True if facet reversed orientation.
 */
 boolT qh_orientoutside(facetT *facet) {
   int k;
   realT dist;
 
   qh_distplane(qh interior_point, facet, &dist);
   if (dist > 0) {
     for (k=qh hull_dim; k--; )
       facet->normal[k]= -facet->normal[k];
     facet->offset= -facet->offset;
     return True;
   }
   return False;
 } /* orientoutside */
 
 /*---------------------------------
 
   qh_outerinner( facet, outerplane, innerplane  )
     if facet and qh.maxoutdone (i.e., qh_check_maxout)
       returns outer and inner plane for facet
     else
       returns maximum outer and inner plane
     accounts for qh.JOGGLEmax
 
   see:
     qh_maxouter(), qh_check_bestdist(), qh_check_points()
 
   notes:
     outerplaner or innerplane may be NULL
     facet is const
     Does not error (QhullFacet)
 
     includes qh.DISTround for actual points
     adds another qh.DISTround if testing with floating point arithmetic
 */
 void qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane) {
   realT dist, mindist;
   vertexT *vertex, **vertexp;
 
   if (outerplane) {
     if (!qh_MAXoutside || !facet || !qh maxoutdone) {
       *outerplane= qh_maxouter();       /* includes qh.DISTround */
     }else { /* qh_MAXoutside ... */
 #if qh_MAXoutside
       *outerplane= facet->maxoutside + qh DISTround;
 #endif
 
     }
     if (qh JOGGLEmax < REALmax/2)
       *outerplane += qh JOGGLEmax * sqrt((realT)qh hull_dim);
   }
   if (innerplane) {
     if (facet) {
       mindist= REALmax;
       FOREACHvertex_(facet->vertices) {
         zinc_(Zdistio);
         qh_distplane(vertex->point, facet, &dist);
         minimize_(mindist, dist);
       }
       *innerplane= mindist - qh DISTround;
     }else
       *innerplane= qh min_vertex - qh DISTround;
     if (qh JOGGLEmax < REALmax/2)
       *innerplane -= qh JOGGLEmax * sqrt((realT)qh hull_dim);
   }
 } /* outerinner */
 
 /*---------------------------------
 
   qh_pointdist( point1, point2, dim )
     return distance between two points
 
   notes:
     returns distance squared if 'dim' is negative
 */
 coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
   coordT dist, diff;
   int k;
 
   dist= 0.0;
   for (k= (dim > 0 ? dim : -dim); k--; ) {
     diff= *point1++ - *point2++;
     dist += diff * diff;
   }
   if (dim > 0)
     return(sqrt(dist));
   return dist;
 } /* pointdist */
 
 
 /*---------------------------------
 
   qh_printmatrix( fp, string, rows, numrow, numcol )
     print matrix to fp given by row vectors
     print string as header
 
   notes:
     print a vector by qh_printmatrix(fp, "", &vect, 1, len)
 */
 void qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol) {
   realT *rowp;
   realT r; /*bug fix*/
   int i,k;
 
   qh_fprintf(fp, 9001, "%s\n", string);
   for (i=0; i < numrow; i++) {
     rowp= rows[i];
     for (k=0; k < numcol; k++) {
       r= *rowp++;
       qh_fprintf(fp, 9002, "%6.3g ", r);
     }
     qh_fprintf(fp, 9003, "\n");
   }
 } /* printmatrix */
 
 
 /*---------------------------------
 
   qh_printpoints( fp, string, points )
     print pointids to fp for a set of points
     if string, prints string and 'p' point ids
 */
 void qh_printpoints(FILE *fp, const char *string, setT *points) {
   pointT *point, **pointp;
 
   if (string) {
     qh_fprintf(fp, 9004, "%s", string);
     FOREACHpoint_(points)
       qh_fprintf(fp, 9005, " p%d", qh_pointid(point));
     qh_fprintf(fp, 9006, "\n");
   }else {
     FOREACHpoint_(points)
       qh_fprintf(fp, 9007, " %d", qh_pointid(point));
     qh_fprintf(fp, 9008, "\n");
   }
 } /* printpoints */
 
 
 /*---------------------------------
 
   qh_projectinput()
     project input points using qh.lower_bound/upper_bound and qh DELAUNAY
     if qh.lower_bound[k]=qh.upper_bound[k]= 0,
       removes dimension k
     if halfspace intersection
       removes dimension k from qh.feasible_point
     input points in qh first_point, num_points, input_dim
 
   returns:
     new point array in qh first_point of qh hull_dim coordinates
     sets qh POINTSmalloc
     if qh DELAUNAY
       projects points to paraboloid
       lowbound/highbound is also projected
     if qh ATinfinity
       adds point "at-infinity"
     if qh POINTSmalloc
       frees old point array
 
   notes:
     checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
 
 
   design:
     sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
     determines newdim and newnum for qh hull_dim and qh num_points
     projects points to newpoints
     projects qh.lower_bound to itself
     projects qh.upper_bound to itself
     if qh DELAUNAY
       if qh ATINFINITY
         projects points to paraboloid
         computes "infinity" point as vertex average and 10% above all points
       else
         uses qh_setdelaunay to project points to paraboloid
 */
 void qh_projectinput(void) {
   int k,i;
   int newdim= qh input_dim, newnum= qh num_points;
   signed char *project;
   int size= (qh input_dim+1)*sizeof(*project);
   pointT *newpoints, *coord, *infinity;
   realT paraboloid, maxboloid= 0;
 
   project= (signed char*)qh_memalloc(size);
   memset((char*)project, 0, (size_t)size);
   for (k=0; k < qh input_dim; k++) {   /* skip Delaunay bound */
     if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) {
       project[k]= -1;
       newdim--;
     }
   }
   if (qh DELAUNAY) {
     project[k]= 1;
     newdim++;
     if (qh ATinfinity)
       newnum++;
   }
   if (newdim != qh hull_dim) {
     qh_fprintf(qh ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   if (!(newpoints=(coordT*)qh_malloc(newnum*newdim*sizeof(coordT)))){
     qh_fprintf(qh ferr, 6016, "qhull error: insufficient memory to project %d points\n",
            qh num_points);
     qh_errexit(qh_ERRmem, NULL, NULL);
   }
   qh_projectpoints(project, qh input_dim+1, qh first_point,
                     qh num_points, qh input_dim, newpoints, newdim);
   trace1((qh ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));
   qh_projectpoints(project, qh input_dim+1, qh lower_bound,
                     1, qh input_dim+1, qh lower_bound, newdim+1);
   qh_projectpoints(project, qh input_dim+1, qh upper_bound,
                     1, qh input_dim+1, qh upper_bound, newdim+1);
   if (qh HALFspace) {
     if (!qh feasible_point) {
       qh_fprintf(qh ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
       qh_errexit(qh_ERRqhull, NULL, NULL);
     }
     qh_projectpoints(project, qh input_dim, qh feasible_point,
                       1, qh input_dim, qh feasible_point, newdim);
   }
   qh_memfree(project, (qh input_dim+1)*sizeof(*project));
   if (qh POINTSmalloc)
     qh_free(qh first_point);
   qh first_point= newpoints;
   qh POINTSmalloc= True;
   if (qh DELAUNAY && qh ATinfinity) {
     coord= qh first_point;
     infinity= qh first_point + qh hull_dim * qh num_points;
     for (k=qh hull_dim-1; k--; )
       infinity[k]= 0.0;
     for (i=qh num_points; i--; ) {
       paraboloid= 0.0;
       for (k=0; k < qh hull_dim-1; k++) {
         paraboloid += *coord * *coord;
         infinity[k] += *coord;
         coord++;
       }
       *(coord++)= paraboloid;
       maximize_(maxboloid, paraboloid);
     }
     /* coord == infinity */
     for (k=qh hull_dim-1; k--; )
       *(coord++) /= qh num_points;
     *(coord++)= maxboloid * 1.1;
     qh num_points++;
     trace0((qh ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
   }else if (qh DELAUNAY)  /* !qh ATinfinity */
     qh_setdelaunay( qh hull_dim, qh num_points, qh first_point);
 } /* projectinput */
 
 
 /*---------------------------------
 
   qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim )
     project points/numpoints/dim to newpoints/newdim
     if project[k] == -1
       delete dimension k
     if project[k] == 1
       add dimension k by duplicating previous column
     n is size of project
 
   notes:
     newpoints may be points if only adding dimension at end
 
   design:
     check that 'project' and 'newdim' agree
     for each dimension
       if project == -1
         skip dimension
       else
         determine start of column in newpoints
         determine start of column in points
           if project == +1, duplicate previous column
         copy dimension (column) from points to newpoints
 */
 void qh_projectpoints(signed char *project, int n, realT *points,
         int numpoints, int dim, realT *newpoints, int newdim) {
   int testdim= dim, oldk=0, newk=0, i,j=0,k;
   realT *newp, *oldp;
 
   for (k=0; k < n; k++)
     testdim += project[k];
   if (testdim != newdim) {
     qh_fprintf(qh ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
       newdim, testdim);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   for (j=0; j= dim)
           continue;
         oldp= points+oldk;
       }else
         oldp= points+oldk++;
       for (i=numpoints; i--; ) {
         *newp= *oldp;
         newp += newdim;
         oldp += dim;
       }
     }
     if (oldk >= dim)
       break;
   }
   trace1((qh ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
     numpoints, dim, newdim));
 } /* projectpoints */
 
 
 /*---------------------------------
 
   qh_rotateinput( rows )
     rotate input using row matrix
     input points given by qh first_point, num_points, hull_dim
     assumes rows[dim] is a scratch buffer
     if qh POINTSmalloc, overwrites input points, else mallocs a new array
 
   returns:
     rotated input
     sets qh POINTSmalloc
 
   design:
     see qh_rotatepoints
 */
 void qh_rotateinput(realT **rows) {
 
   if (!qh POINTSmalloc) {
     qh first_point= qh_copypoints(qh first_point, qh num_points, qh hull_dim);
     qh POINTSmalloc= True;
   }
   qh_rotatepoints(qh first_point, qh num_points, qh hull_dim, rows);
 }  /* rotateinput */
 
 /*---------------------------------
 
   qh_rotatepoints( points, numpoints, dim, row )
     rotate numpoints points by a d-dim row matrix
     assumes rows[dim] is a scratch buffer
 
   returns:
     rotated points in place
 
   design:
     for each point
       for each coordinate
         use row[dim] to compute partial inner product
       for each coordinate
         rotate by partial inner product
 */
 void qh_rotatepoints(realT *points, int numpoints, int dim, realT **row) {
   realT *point, *rowi, *coord= NULL, sum, *newval;
   int i,j,k;
 
   if (qh IStracing >= 1)
     qh_printmatrix(qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
   for (point= points, j= numpoints; j--; point += dim) {
     newval= row[dim];
     for (i=0; i < dim; i++) {
       rowi= row[i];
       coord= point;
       for (sum= 0.0, k= dim; k--; )
         sum += *rowi++ * *coord++;
       *(newval++)= sum;
     }
     for (k=dim; k--; )
       *(--coord)= *(--newval);
   }
 } /* rotatepoints */
 
 
 /*---------------------------------
 
   qh_scaleinput()
     scale input points using qh low_bound/high_bound
     input points given by qh first_point, num_points, hull_dim
     if qh POINTSmalloc, overwrites input points, else mallocs a new array
 
   returns:
     scales coordinates of points to low_bound[k], high_bound[k]
     sets qh POINTSmalloc
 
   design:
     see qh_scalepoints
 */
 void qh_scaleinput(void) {
 
   if (!qh POINTSmalloc) {
     qh first_point= qh_copypoints(qh first_point, qh num_points, qh hull_dim);
     qh POINTSmalloc= True;
   }
   qh_scalepoints(qh first_point, qh num_points, qh hull_dim,
        qh lower_bound, qh upper_bound);
 }  /* scaleinput */
 
 /*---------------------------------
 
   qh_scalelast( points, numpoints, dim, low, high, newhigh )
     scale last coordinate to [0,m] for Delaunay triangulations
     input points given by points, numpoints, dim
 
   returns:
     changes scale of last coordinate from [low, high] to [0, newhigh]
     overwrites last coordinate of each point
     saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
 
   notes:
     when called by qh_setdelaunay, low/high may not match actual data
 
   design:
     compute scale and shift factors
     apply to last coordinate of each point
 */
 void qh_scalelast(coordT *points, int numpoints, int dim, coordT low,
                    coordT high, coordT newhigh) {
   realT scale, shift;
   coordT *coord;
   int i;
   boolT nearzero= False;
 
   trace4((qh ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",
     low, high, newhigh));
   qh last_low= low;
   qh last_high= high;
   qh last_newhigh= newhigh;
   scale= qh_divzero(newhigh, high - low,
                   qh MINdenom_1, &nearzero);
   if (nearzero) {
     if (qh DELAUNAY)
       qh_fprintf(qh ferr, 6019, "qhull input error: can not scale last coordinate.  Input is cocircular\n   or cospherical.   Use option 'Qz' to add a point at infinity.\n");
     else
       qh_fprintf(qh ferr, 6020, "qhull input error: can not scale last coordinate.  New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",
                 newhigh, low, high, high-low);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   shift= - low * newhigh / (high-low);
   coord= points + dim - 1;
   for (i=numpoints; i--; coord += dim)
     *coord= *coord * scale + shift;
 } /* scalelast */
 
 /*---------------------------------
 
   qh_scalepoints( points, numpoints, dim, newlows, newhighs )
     scale points to new lowbound and highbound
     retains old bound when newlow= -REALmax or newhigh= +REALmax
 
   returns:
     scaled points
     overwrites old points
 
   design:
     for each coordinate
       compute current low and high bound
       compute scale and shift factors
       scale all points
       enforce new low and high bound for all points
 */
 void qh_scalepoints(pointT *points, int numpoints, int dim,
         realT *newlows, realT *newhighs) {
   int i,k;
   realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
   boolT nearzero= False;
 
   for (k=0; k < dim; k++) {
     newhigh= newhighs[k];
     newlow= newlows[k];
     if (newhigh > REALmax/2 && newlow < -REALmax/2)
       continue;
     low= REALmax;
     high= -REALmax;
     for (i=numpoints, coord=points+k; i--; coord += dim) {
       minimize_(low, *coord);
       maximize_(high, *coord);
     }
     if (newhigh > REALmax/2)
       newhigh= high;
     if (newlow < -REALmax/2)
       newlow= low;
     if (qh DELAUNAY && k == dim-1 && newhigh < newlow) {
       qh_fprintf(qh ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
                k, k, newhigh, newlow);
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     scale= qh_divzero(newhigh - newlow, high - low,
                   qh MINdenom_1, &nearzero);
     if (nearzero) {
       qh_fprintf(qh ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
               k, newlow, newhigh, low, high);
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     shift= (newlow * high - low * newhigh)/(high-low);
     coord= points+k;
     for (i=numpoints; i--; coord += dim)
       *coord= *coord * scale + shift;
     coord= points+k;
     if (newlow < newhigh) {
       mincoord= newlow;
       maxcoord= newhigh;
     }else {
       mincoord= newhigh;
       maxcoord= newlow;
     }
     for (i=numpoints; i--; coord += dim) {
       minimize_(*coord, maxcoord);  /* because of roundoff error */
       maximize_(*coord, mincoord);
     }
     trace0((qh ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
       k, low, high, newlow, newhigh, numpoints, scale, shift));
   }
 } /* scalepoints */
 
 
 /*---------------------------------
 
   qh_setdelaunay( dim, count, points )
     project count points to dim-d paraboloid for Delaunay triangulation
 
     dim is one more than the dimension of the input set
     assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
 
     points is a dim*count realT array.  The first dim-1 coordinates
     are the coordinates of the first input point.  array[dim] is
     the first coordinate of the second input point.  array[2*dim] is
     the first coordinate of the third input point.
 
     if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
       calls qh_scalelast to scale the last coordinate the same as the other points
 
   returns:
     for each point
       sets point[dim-1] to sum of squares of coordinates
     scale points to 'Qbb' if needed
 
   notes:
     to project one point, use
       qh_setdelaunay(qh hull_dim, 1, point)
 
     Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
     the coordinates after the original projection.
 
 */
 void qh_setdelaunay(int dim, int count, pointT *points) {
   int i, k;
   coordT *coordp, coord;
   realT paraboloid;
 
   trace0((qh ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
   coordp= points;
   for (i=0; i < count; i++) {
     coord= *coordp++;
     paraboloid= coord*coord;
     for (k=dim-2; k--; ) {
       coord= *coordp++;
       paraboloid += coord*coord;
     }
     *coordp++ = paraboloid;
   }
   if (qh last_low < REALmax/2)
     qh_scalelast(points, count, dim, qh last_low, qh last_high, qh last_newhigh);
 } /* setdelaunay */
 
 
 /*---------------------------------
 
   qh_sethalfspace( dim, coords, nextp, normal, offset, feasible )
     set point to dual of halfspace relative to feasible point
     halfspace is normal coefficients and offset.
 
   returns:
     false if feasible point is outside of hull (error message already reported)
     overwrites coordinates for point at dim coords
     nextp= next point (coords)
 
   design:
     compute distance from feasible point to halfspace
     divide each normal coefficient by -dist
 */
 boolT qh_sethalfspace(int dim, coordT *coords, coordT **nextp,
          coordT *normal, coordT *offset, coordT *feasible) {
   coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
   realT dist;
   realT r; /*bug fix*/
   int k;
   boolT zerodiv;
 
   dist= *offset;
   for (k=dim; k--; )
     dist += *(normp++) * *(feasiblep++);
   if (dist > 0)
     goto LABELerroroutside;
   normp= normal;
   if (dist < -qh MINdenom) {
     for (k=dim; k--; )
       *(coordp++)= *(normp++) / -dist;
   }else {
     for (k=dim; k--; ) {
       *(coordp++)= qh_divzero(*(normp++), -dist, qh MINdenom_1, &zerodiv);
       if (zerodiv)
         goto LABELerroroutside;
     }
   }
   *nextp= coordp;
   if (qh IStracing >= 4) {
     qh_fprintf(qh ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
     for (k=dim, coordp=coords; k--; ) {
       r= *coordp++;
       qh_fprintf(qh ferr, 8022, " %6.2g", r);
     }
     qh_fprintf(qh ferr, 8023, "\n");
   }
   return True;
 LABELerroroutside:
   feasiblep= feasible;
   normp= normal;
   qh_fprintf(qh ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
   for (k=dim; k--; )
     qh_fprintf(qh ferr, 8024, qh_REAL_1, r=*(feasiblep++));
   qh_fprintf(qh ferr, 8025, "\n     halfspace: ");
   for (k=dim; k--; )
     qh_fprintf(qh ferr, 8026, qh_REAL_1, r=*(normp++));
   qh_fprintf(qh ferr, 8027, "\n     at offset: ");
   qh_fprintf(qh ferr, 8028, qh_REAL_1, *offset);
   qh_fprintf(qh ferr, 8029, " and distance: ");
   qh_fprintf(qh ferr, 8030, qh_REAL_1, dist);
   qh_fprintf(qh ferr, 8031, "\n");
   return False;
 } /* sethalfspace */
 
 /*---------------------------------
 
   qh_sethalfspace_all( dim, count, halfspaces, feasible )
     generate dual for halfspace intersection with feasible point
     array of count halfspaces
       each halfspace is normal coefficients followed by offset
       the origin is inside the halfspace if the offset is negative
 
   returns:
     malloc'd array of count X dim-1 points
 
   notes:
     call before qh_init_B or qh_initqhull_globals
     unused/untested code: please email bradb@shore.net if this works ok for you
     If using option 'Fp', also set qh feasible_point. It is a malloc'd array
       that is freed by qh_freebuffers.
 
   design:
     see qh_sethalfspace
 */
 coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible) {
   int i, newdim;
   pointT *newpoints;
   coordT *coordp, *normalp, *offsetp;
 
   trace0((qh ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
   newdim= dim - 1;
   if (!(newpoints=(coordT*)qh_malloc(count*newdim*sizeof(coordT)))){
     qh_fprintf(qh ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
           count);
     qh_errexit(qh_ERRmem, NULL, NULL);
   }
   coordp= newpoints;
   normalp= halfspaces;
   for (i=0; i < count; i++) {
     offsetp= normalp + newdim;
     if (!qh_sethalfspace(newdim, coordp, &coordp, normalp, offsetp, feasible)) {
       qh_fprintf(qh ferr, 8032, "The halfspace was at index %d\n", i);
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     normalp= offsetp + 1;
   }
   return newpoints;
 } /* sethalfspace_all */
 
 
 /*---------------------------------
 
   qh_sharpnewfacets()
 
   returns:
     true if could be an acute angle (facets in different quadrants)
 
   notes:
     for qh_findbest
 
   design:
     for all facets on qh.newfacet_list
       if two facets are in different quadrants
         set issharp
 */
 boolT qh_sharpnewfacets() {
   facetT *facet;
   boolT issharp = False;
   int *quadrant, k;
 
   quadrant= (int*)qh_memalloc(qh hull_dim * sizeof(int));
   FORALLfacet_(qh newfacet_list) {
     if (facet == qh newfacet_list) {
       for (k=qh hull_dim; k--; )
         quadrant[ k]= (facet->normal[ k] > 0);
     }else {
       for (k=qh hull_dim; k--; ) {
         if (quadrant[ k] != (facet->normal[ k] > 0)) {
           issharp= True;
           break;
         }
       }
     }
     if (issharp)
       break;
   }
   qh_memfree( quadrant, qh hull_dim * sizeof(int));
   trace3((qh ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));
   return issharp;
 } /* sharpnewfacets */
 
 /*---------------------------------
 
   qh_voronoi_center( dim, points )
     return Voronoi center for a set of points
     dim is the orginal dimension of the points
     gh.gm_matrix/qh.gm_row are scratch buffers
 
   returns:
     center as a temporary point
     if non-simplicial,
       returns center for max simplex of points
 
   notes:
     from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
 
   design:
     if non-simplicial
       determine max simplex for points
     translate point0 of simplex to origin
     compute sum of squares of diagonal
     compute determinate
     compute Voronoi center (see Bowyer & Woodwark)
 */
 pointT *qh_voronoi_center(int dim, setT *points) {
   pointT *point, **pointp, *point0;
   pointT *center= (pointT*)qh_memalloc(qh center_size);
   setT *simplex;
   int i, j, k, size= qh_setsize(points);
   coordT *gmcoord;
   realT *diffp, sum2, *sum2row, *sum2p, det, factor;
   boolT nearzero, infinite;
 
   if (size == dim+1)
     simplex= points;
   else if (size < dim+1) {
     qh_fprintf(qh ferr, 6025, "qhull internal error (qh_voronoi_center):\n  need at least %d points to construct a Voronoi center\n",
              dim+1);
     qh_errexit(qh_ERRqhull, NULL, NULL);
     simplex= points;  /* never executed -- avoids warning */
   }else {
     simplex= qh_settemp(dim+1);
     qh_maxsimplex(dim, points, NULL, 0, &simplex);
   }
   point0= SETfirstt_(simplex, pointT);
   gmcoord= qh gm_matrix;
   for (k=0; k < dim; k++) {
     qh gm_row[k]= gmcoord;
     FOREACHpoint_(simplex) {
       if (point != point0)
         *(gmcoord++)= point[k] - point0[k];
     }
   }
   sum2row= gmcoord;
   for (i=0; i < dim; i++) {
     sum2= 0.0;
     for (k=0; k < dim; k++) {
       diffp= qh gm_row[k] + i;
       sum2 += *diffp * *diffp;
     }
     *(gmcoord++)= sum2;
   }
   det= qh_determinant(qh gm_row, dim, &nearzero);
   factor= qh_divzero(0.5, det, qh MINdenom, &infinite);
   if (infinite) {
     for (k=dim; k--; )
       center[k]= qh_INFINITE;
     if (qh IStracing)
       qh_printpoints(qh ferr, "qh_voronoi_center: at infinity for ", simplex);
   }else {
     for (i=0; i < dim; i++) {
       gmcoord= qh gm_matrix;
       sum2p= sum2row;
       for (k=0; k < dim; k++) {
         qh gm_row[k]= gmcoord;
         if (k == i) {
           for (j=dim; j--; )
             *(gmcoord++)= *sum2p++;
         }else {
           FOREACHpoint_(simplex) {
             if (point != point0)
               *(gmcoord++)= point[k] - point0[k];
           }
         }
       }
       center[i]= qh_determinant(qh gm_row, dim, &nearzero)*factor + point0[i];
     }
 #ifndef qh_NOtrace
     if (qh IStracing >= 3) {
       qh_fprintf(qh ferr, 8033, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
       qh_printmatrix(qh ferr, "center:", ¢er, 1, dim);
       if (qh IStracing >= 5) {
         qh_printpoints(qh ferr, "points", simplex);
         FOREACHpoint_(simplex)
           qh_fprintf(qh ferr, 8034, "p%d dist %.2g, ", qh_pointid(point),
                    qh_pointdist(point, center, dim));
         qh_fprintf(qh ferr, 8035, "\n");
       }
     }
 #endif
   }
   if (simplex != points)
     qh_settempfree(&simplex);
   return center;
 } /* voronoi_center */
 
diff --git a/src/libqhull/global.c b/src/libqhull/global.c
index 147cf42..f3f3114 100644
--- a/src/libqhull/global.c
+++ b/src/libqhull/global.c
@@ -1,2129 +1,2129 @@
 
 /*
  ---------------------------------
 
    global.c
    initializes all the globals of the qhull application
 
    see README
 
    see libqhull.h for qh.globals and function prototypes
 
    see qhull_a.h for internal functions
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/global.c#17 $$Change: 1709 $
-   $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/global.c#18 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
  */
 
 #include "qhull_a.h"
 
 /*========= qh definition -- globals defined in libqhull.h =======================*/
 
 int qhull_inuse= 0; /* not used */
 
 #if qh_QHpointer
 qhT *qh_qh= NULL;       /* pointer to all global variables */
 #else
 qhT qh_qh;              /* all global variables.
                            Add "= {0}" if this causes a compiler error.
                            Also qh_qhstat in stat.c and qhmem in mem.c.  */
 #endif
 
 /*----------------------------------
 
   qh_version
     version string by year and date
 
     the revision increases on code changes only
 
   notes:
     change date:    Changes.txt, Announce.txt, index.htm, README.txt,
                     qhull-news.html, Eudora signatures, CMakeLists.txt
     change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt
     change year:    Copying.txt
     check download size
     recompile user_eg.c, rbox.c, libqhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c, testqset.c
 */
 
 const char *qh_version = "2012.1 2012/02/18";
 
 /*---------------------------------
 
   qh_appendprint( printFormat )
     append printFormat to qh.PRINTout unless already defined
 */
 void qh_appendprint(qh_PRINT format) {
   int i;
 
   for (i=0; i < qh_PRINTEND; i++) {
     if (qh PRINTout[i] == format && format != qh_PRINTqhull)
       break;
     if (!qh PRINTout[i]) {
       qh PRINTout[i]= format;
       break;
     }
   }
 } /* appendprint */
 
 /*---------------------------------
 
   qh_checkflags( commandStr, hiddenFlags )
     errors if commandStr contains hiddenFlags
     hiddenFlags starts and ends with a space and is space deliminated (checked)
 
   notes:
     ignores first word (e.g., "qconvex i")
     use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
 
   see:
     qh_initflags() initializes Qhull according to commandStr
 */
 void qh_checkflags(char *command, char *hiddenflags) {
   char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */
   char key, opt, prevopt;
   char chkkey[]= "   ";
   char chkopt[]=  "    ";
   char chkopt2[]= "     ";
   boolT waserr= False;
 
   if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
     qh_fprintf(qh ferr, 6026, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (strpbrk(hiddenflags, ",\n\r\t")) {
     qh_fprintf(qh ferr, 6027, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   while (*s && !isspace(*s))  /* skip program name */
     s++;
   while (*s) {
     while (*s && isspace(*s))
       s++;
     if (*s == '-')
       s++;
     if (!*s)
       break;
     key = *s++;
     chkerr = NULL;
     if (key == 'T' && (*s == 'I' || *s == 'O')) {  /* TI or TO 'file name' */
       s= qh_skipfilename(++s);
       continue;
     }
     chkkey[1]= key;
     if (strstr(hiddenflags, chkkey)) {
       chkerr= chkkey;
     }else if (isupper(key)) {
       opt= ' ';
       prevopt= ' ';
       chkopt[1]= key;
       chkopt2[1]= key;
       while (!chkerr && *s && !isspace(*s)) {
         opt= *s++;
         if (isalpha(opt)) {
           chkopt[2]= opt;
           if (strstr(hiddenflags, chkopt))
             chkerr= chkopt;
           if (prevopt != ' ') {
             chkopt2[2]= prevopt;
             chkopt2[3]= opt;
             if (strstr(hiddenflags, chkopt2))
               chkerr= chkopt2;
           }
         }else if (key == 'Q' && isdigit(opt) && prevopt != 'b'
               && (prevopt == ' ' || islower(prevopt))) {
             chkopt[2]= opt;
             if (strstr(hiddenflags, chkopt))
               chkerr= chkopt;
         }else {
           qh_strtod(s-1, &t);
           if (s < t)
             s= t;
         }
         prevopt= opt;
       }
     }
     if (chkerr) {
       *chkerr= '\'';
       chkerr[strlen(chkerr)-1]=  '\'';
       qh_fprintf(qh ferr, 6029, "qhull error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
       waserr= True;
     }
   }
   if (waserr)
     qh_errexit(qh_ERRinput, NULL, NULL);
 } /* checkflags */
 
 /*---------------------------------
 
   qh_clear_outputflags()
     Clear output flags for QhullPoints
 */
 void qh_clear_outputflags(void) {
   int i,k;
 
   qh ANNOTATEoutput= False;
   qh DOintersections= False;
   qh DROPdim= -1;
   qh FORCEoutput= False;
   qh GETarea= False;
   qh GOODpoint= 0;
   qh GOODpointp= NULL;
   qh GOODthreshold= False;
   qh GOODvertex= 0;
   qh GOODvertexp= NULL;
   qh IStracing= 0;
   qh KEEParea= False;
   qh KEEPmerge= False;
   qh KEEPminArea= REALmax;
   qh PRINTcentrums= False;
   qh PRINTcoplanar= False;
   qh PRINTdots= False;
   qh PRINTgood= False;
   qh PRINTinner= False;
   qh PRINTneighbors= False;
   qh PRINTnoplanes= False;
   qh PRINToptions1st= False;
   qh PRINTouter= False;
   qh PRINTprecision= True;
   qh PRINTridges= False;
   qh PRINTspheres= False;
   qh PRINTstatistics= False;
   qh PRINTsummary= False;
   qh PRINTtransparent= False;
   qh SPLITthresholds= False;
   qh TRACElevel= 0;
   qh TRInormals= False;
   qh USEstdout= False;
   qh VERIFYoutput= False;
   for (k=qh input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_ouputflags */
     qh lower_threshold[k]= -REALmax;
     qh upper_threshold[k]= REALmax;
     qh lower_bound[k]= -REALmax;
     qh upper_bound[k]= REALmax;
   }
 
   for (i=0; i < qh_PRINTEND; i++) {
     qh PRINTout[i]= qh_PRINTnone;
   }
 
   if (!qh qhull_commandsiz2)
       qh qhull_commandsiz2= (int)strlen(qh qhull_command); /* WARN64 */
   else {
       qh qhull_command[qh qhull_commandsiz2]= '\0';
   }
   if (!qh qhull_optionsiz2)
     qh qhull_optionsiz2= (int)strlen(qh qhull_options);  /* WARN64 */
   else {
     qh qhull_options[qh qhull_optionsiz2]= '\0';
     qh qhull_optionlen= qh_OPTIONline;  /* start a new line */
   }
 } /* clear_outputflags */
 
 /*---------------------------------
 
   qh_clock()
     return user CPU time in 100ths (qh_SECtick)
     only defined for qh_CLOCKtype == 2
 
   notes:
     use first value to determine time 0
     from Stevens '92 8.15
 */
 unsigned long qh_clock(void) {
 
 #if (qh_CLOCKtype == 2)
   struct tms time;
   static long clktck;  /* initialized first call */
   double ratio, cpu;
   unsigned long ticks;
 
   if (!clktck) {
     if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {
       qh_fprintf(qh ferr, 6030, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user.h\n");
       qh_errexit(qh_ERRqhull, NULL, NULL);
     }
   }
   if (times(&time) == -1) {
     qh_fprintf(qh ferr, 6031, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user.h\n");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   ratio= qh_SECticks / (double)clktck;
   ticks= time.tms_utime * ratio;
   return ticks;
 #else
   qh_fprintf(qh ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");
   qh_errexit(qh_ERRqhull, NULL, NULL); /* never returns */
   return 0;
 #endif
 } /* clock */
 
 /*---------------------------------
 
   qh_freebuffers()
     free up global memory buffers
 
   notes:
     must match qh_initbuffers()
 */
 void qh_freebuffers(void) {
 
   trace5((qh ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));
   /* allocated by qh_initqhull_buffers */
   qh_memfree(qh NEARzero, qh hull_dim * sizeof(realT));
   qh_memfree(qh lower_threshold, (qh input_dim+1) * sizeof(realT));
   qh_memfree(qh upper_threshold, (qh input_dim+1) * sizeof(realT));
   qh_memfree(qh lower_bound, (qh input_dim+1) * sizeof(realT));
   qh_memfree(qh upper_bound, (qh input_dim+1) * sizeof(realT));
   qh_memfree(qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT));
   qh_memfree(qh gm_row, (qh hull_dim+1) * sizeof(coordT *));
   qh NEARzero= qh lower_threshold= qh upper_threshold= NULL;
   qh lower_bound= qh upper_bound= NULL;
   qh gm_matrix= NULL;
   qh gm_row= NULL;
   qh_setfree(&qh other_points);
   qh_setfree(&qh del_vertices);
   qh_setfree(&qh coplanarfacetset);
   if (qh line)                /* allocated by qh_readinput, freed if no error */
     qh_free(qh line);
   if (qh half_space)
     qh_free(qh half_space);
   if (qh temp_malloc)
     qh_free(qh temp_malloc);
   if (qh feasible_point)      /* allocated by qh_readfeasible */
     qh_free(qh feasible_point);
   if (qh feasible_string)     /* allocated by qh_initflags */
     qh_free(qh feasible_string);
   qh line= qh feasible_string= NULL;
   qh half_space= qh feasible_point= qh temp_malloc= NULL;
   /* usually allocated by qh_readinput */
   if (qh first_point && qh POINTSmalloc) {
     qh_free(qh first_point);
     qh first_point= NULL;
   }
   if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */
     qh_free(qh input_points);
     qh input_points= NULL;
   }
   trace5((qh ferr, 5002, "qh_freebuffers: finished\n"));
 } /* freebuffers */
 
 
 /*---------------------------------
 
   qh_freebuild( allmem )
     free global memory used by qh_initbuild and qh_buildhull
     if !allmem,
       does not free short memory (e.g., facetT, freed by qh_memfreeshort)
 
   design:
     free centrums
     free each vertex
     mark unattached ridges
     for each facet
       free ridges
       free outside set, coplanar set, neighbor set, ridge set, vertex set
       free facet
     free hash table
     free interior point
     free merge set
     free temporary sets
 */
 void qh_freebuild(boolT allmem) {
   facetT *facet;
   vertexT *vertex;
   ridgeT *ridge, **ridgep;
   mergeT *merge, **mergep;
 
   trace1((qh ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
   if (qh del_vertices)
     qh_settruncate(qh del_vertices, 0);
   if (allmem) {
     while ((vertex= qh vertex_list)) {
       if (vertex->next)
         qh_delvertex(vertex);
       else {
         qh_memfree(vertex, (int)sizeof(vertexT));
         qh newvertex_list= qh vertex_list= NULL;
       }
     }
   }else if (qh VERTEXneighbors) {
     FORALLvertices
       qh_setfreelong(&(vertex->neighbors));
   }
   qh VERTEXneighbors= False;
   qh GOODclosest= NULL;
   if (allmem) {
     FORALLfacets {
       FOREACHridge_(facet->ridges)
         ridge->seen= False;
     }
     FORALLfacets {
       if (facet->visible) {
         FOREACHridge_(facet->ridges) {
           if (!otherfacet_(ridge, facet)->visible)
             ridge->seen= True;  /* an unattached ridge */
         }
       }
     }
     while ((facet= qh facet_list)) {
       FOREACHridge_(facet->ridges) {
         if (ridge->seen) {
           qh_setfree(&(ridge->vertices));
           qh_memfree(ridge, (int)sizeof(ridgeT));
         }else
           ridge->seen= True;
       }
       qh_setfree(&(facet->outsideset));
       qh_setfree(&(facet->coplanarset));
       qh_setfree(&(facet->neighbors));
       qh_setfree(&(facet->ridges));
       qh_setfree(&(facet->vertices));
       if (facet->next)
         qh_delfacet(facet);
       else {
         qh_memfree(facet, (int)sizeof(facetT));
         qh visible_list= qh newfacet_list= qh facet_list= NULL;
       }
     }
   }else {
     FORALLfacets {
       qh_setfreelong(&(facet->outsideset));
       qh_setfreelong(&(facet->coplanarset));
       if (!facet->simplicial) {
         qh_setfreelong(&(facet->neighbors));
         qh_setfreelong(&(facet->ridges));
         qh_setfreelong(&(facet->vertices));
       }
     }
   }
   qh_setfree(&(qh hash_table));
   qh_memfree(qh interior_point, qh normal_size);
   qh interior_point= NULL;
   FOREACHmerge_(qh facet_mergeset)  /* usually empty */
     qh_memfree(merge, (int)sizeof(mergeT));
   qh facet_mergeset= NULL;  /* temp set */
   qh degen_mergeset= NULL;  /* temp set */
   qh_settempfree_all();
 } /* freebuild */
 
 /*---------------------------------
 
   qh_freeqhull( allmem )
     see qh_freeqhull2
     if qh_QHpointer, frees qh_qh
 */
 void qh_freeqhull(boolT allmem) {
     qh_freeqhull2(allmem);
 #if qh_QHpointer
     qh_free(qh_qh);
     qh_qh= NULL;
 #endif
 }
 
 /*---------------------------------
 
 qh_freeqhull2( allmem )
   free global memory
   if !allmem,
     does not free short memory (freed by qh_memfreeshort)
 
 notes:
   sets qh.NOerrexit in case caller forgets to
 
 see:
   see qh_initqhull_start2()
 
 design:
   free global and temporary memory from qh_initbuild and qh_buildhull
   free buffers
   free statistics
 */
 void qh_freeqhull2(boolT allmem) {
 
   trace1((qh ferr, 1006, "qh_freeqhull2: free global memory\n"));
   qh NOerrexit= True;  /* no more setjmp since called at exit and ~QhullQh */
   qh_freebuild(allmem);
   qh_freebuffers();
   qh_freestatistics();
 #if qh_QHpointer
   memset((char *)qh_qh, 0, sizeof(qhT));
   /* qh_qh freed by caller, qh_freeqhull() */
 #else
   memset((char *)&qh_qh, 0, sizeof(qhT));
 #endif
   qh NOerrexit= True;
 } /* freeqhull2 */
 
 /*---------------------------------
 
   qh_init_A( infile, outfile, errfile, argc, argv )
     initialize memory and stdio files
     convert input options to option string (qh.qhull_command)
 
   notes:
     infile may be NULL if qh_readpoints() is not called
 
     errfile should always be defined.  It is used for reporting
     errors.  outfile is used for output and format options.
 
     argc/argv may be 0/NULL
 
     called before error handling initialized
     qh_errexit() may not be used
 */
 void qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
   qh_meminit(errfile);
   qh_initqhull_start(infile, outfile, errfile);
   qh_init_qhull_command(argc, argv);
 } /* init_A */
 
 /*---------------------------------
 
   qh_init_B( points, numpoints, dim, ismalloc )
     initialize globals for points array
 
     points has numpoints dim-dimensional points
       points[0] is the first coordinate of the first point
       points[1] is the second coordinate of the first point
       points[dim] is the first coordinate of the second point
 
     ismalloc=True
       Qhull will call qh_free(points) on exit or input transformation
     ismalloc=False
       Qhull will allocate a new point array if needed for input transformation
 
     qh.qhull_command
       is the option string.
       It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags
 
   returns:
     if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
       projects the input to a new point array
 
         if qh.DELAUNAY,
           qh.hull_dim is increased by one
         if qh.ATinfinity,
           qh_projectinput adds point-at-infinity for Delaunay tri.
 
     if qh.SCALEinput
       changes the upper and lower bounds of the input, see qh_scaleinput()
 
     if qh.ROTATEinput
       rotates the input by a random rotation, see qh_rotateinput()
       if qh.DELAUNAY
         rotates about the last coordinate
 
   notes:
     called after points are defined
     qh_errexit() may be used
 */
 void qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc) {
   qh_initqhull_globals(points, numpoints, dim, ismalloc);
   if (qhmem.LASTsize == 0)
     qh_initqhull_mem();
   /* mem.c and qset.c are initialized */
   qh_initqhull_buffers();
   qh_initthresholds(qh qhull_command);
   if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay))
     qh_projectinput();
   if (qh SCALEinput)
     qh_scaleinput();
   if (qh ROTATErandom >= 0) {
     qh_randommatrix(qh gm_matrix, qh hull_dim, qh gm_row);
     if (qh DELAUNAY) {
       int k, lastk= qh hull_dim-1;
       for (k=0; k < lastk; k++) {
         qh gm_row[k][lastk]= 0.0;
         qh gm_row[lastk][k]= 0.0;
       }
       qh gm_row[lastk][lastk]= 1.0;
     }
     qh_gram_schmidt(qh hull_dim, qh gm_row);
     qh_rotateinput(qh gm_row);
   }
 } /* init_B */
 
 /*---------------------------------
 
   qh_init_qhull_command( argc, argv )
     build qh.qhull_command from argc/argv
 
   returns:
     a space-delimited string of options (just as typed)
 
   notes:
     makes option string easy to input and output
 
     argc/argv may be 0/NULL
 */
 void qh_init_qhull_command(int argc, char *argv[]) {
 
   if (!qh_argv_to_command(argc, argv, qh qhull_command, (int)sizeof(qh qhull_command))){
     /* Assumes qh.ferr is defined. */
     qh_fprintf(qh ferr, 6033, "qhull input error: more than %d characters in command line\n",
           (int)sizeof(qh qhull_command));
     qh_exit(qh_ERRinput);  /* error reported, can not use qh_errexit */
   }
 } /* init_qhull_command */
 
 /*---------------------------------
 
   qh_initflags( commandStr )
     set flags and initialized constants from commandStr
 
   returns:
     sets qh.qhull_command to command if needed
 
   notes:
     ignores first word (e.g., "qhull d")
     use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
 
   see:
     qh_initthresholds() continues processing of 'Pdn' and 'PDn'
     'prompt' in unix.c for documentation
 
   design:
     for each space-deliminated option group
       if top-level option
         check syntax
         append approriate option to option string
         set appropriate global variable or append printFormat to print options
       else
         for each sub-option
           check syntax
           append approriate option to option string
           set appropriate global variable or append printFormat to print options
 */
 void qh_initflags(char *command) {
   int k, i, lastproject;
   char *s= command, *t, *prev_s, *start, key;
   boolT isgeom= False, wasproject;
   realT r;
 
   if (command <= &qh qhull_command[0] || command > &qh qhull_command[0] + sizeof(qh qhull_command)) {
     if (command != &qh qhull_command[0]) {
       *qh qhull_command= '\0';
       strncat(qh qhull_command, command, sizeof(qh qhull_command)-strlen(qh qhull_command)-1);
     }
     while (*s && !isspace(*s))  /* skip program name */
       s++;
   }
   while (*s) {
     while (*s && isspace(*s))
       s++;
     if (*s == '-')
       s++;
     if (!*s)
       break;
     prev_s= s;
     switch (*s++) {
     case 'd':
       qh_option("delaunay", NULL, NULL);
       qh DELAUNAY= True;
       break;
     case 'f':
       qh_option("facets", NULL, NULL);
       qh_appendprint(qh_PRINTfacets);
       break;
     case 'i':
       qh_option("incidence", NULL, NULL);
       qh_appendprint(qh_PRINTincidences);
       break;
     case 'm':
       qh_option("mathematica", NULL, NULL);
       qh_appendprint(qh_PRINTmathematica);
       break;
     case 'n':
       qh_option("normals", NULL, NULL);
       qh_appendprint(qh_PRINTnormals);
       break;
     case 'o':
       qh_option("offFile", NULL, NULL);
       qh_appendprint(qh_PRINToff);
       break;
     case 'p':
       qh_option("points", NULL, NULL);
       qh_appendprint(qh_PRINTpoints);
       break;
     case 's':
       qh_option("summary", NULL, NULL);
       qh PRINTsummary= True;
       break;
     case 'v':
       qh_option("voronoi", NULL, NULL);
       qh VORONOI= True;
       qh DELAUNAY= True;
       break;
     case 'A':
       if (!isdigit(*s) && *s != '.' && *s != '-')
         qh_fprintf(qh ferr, 7002, "qhull warning: no maximum cosine angle given for option 'An'.  Ignored.\n");
       else {
         if (*s == '-') {
           qh premerge_cos= -qh_strtod(s, &s);
           qh_option("Angle-premerge-", NULL, &qh premerge_cos);
           qh PREmerge= True;
         }else {
           qh postmerge_cos= qh_strtod(s, &s);
           qh_option("Angle-postmerge", NULL, &qh postmerge_cos);
           qh POSTmerge= True;
         }
         qh MERGING= True;
       }
       break;
     case 'C':
       if (!isdigit(*s) && *s != '.' && *s != '-')
         qh_fprintf(qh ferr, 7003, "qhull warning: no centrum radius given for option 'Cn'.  Ignored.\n");
       else {
         if (*s == '-') {
           qh premerge_centrum= -qh_strtod(s, &s);
           qh_option("Centrum-premerge-", NULL, &qh premerge_centrum);
           qh PREmerge= True;
         }else {
           qh postmerge_centrum= qh_strtod(s, &s);
           qh_option("Centrum-postmerge", NULL, &qh postmerge_centrum);
           qh POSTmerge= True;
         }
         qh MERGING= True;
       }
       break;
     case 'E':
       if (*s == '-')
         qh_fprintf(qh ferr, 7004, "qhull warning: negative maximum roundoff given for option 'An'.  Ignored.\n");
       else if (!isdigit(*s))
         qh_fprintf(qh ferr, 7005, "qhull warning: no maximum roundoff given for option 'En'.  Ignored.\n");
       else {
         qh DISTround= qh_strtod(s, &s);
         qh_option("Distance-roundoff", NULL, &qh DISTround);
         qh SETroundoff= True;
       }
       break;
     case 'H':
       start= s;
       qh HALFspace= True;
       qh_strtod(s, &t);
       while (t > s)  {
         if (*t && !isspace(*t)) {
           if (*t == ',')
             t++;
           else
             qh_fprintf(qh ferr, 7006, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n");
         }
         s= t;
         qh_strtod(s, &t);
       }
       if (start < t) {
         if (!(qh feasible_string= (char*)calloc((size_t)(t-start+1), (size_t)1))) {
           qh_fprintf(qh ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");
           qh_errexit(qh_ERRmem, NULL, NULL);
         }
         strncpy(qh feasible_string, start, (size_t)(t-start));
         qh_option("Halfspace-about", NULL, NULL);
         qh_option(qh feasible_string, NULL, NULL);
       }else
         qh_option("Halfspace", NULL, NULL);
       break;
     case 'R':
       if (!isdigit(*s))
         qh_fprintf(qh ferr, 7007, "qhull warning: missing random perturbation for option 'Rn'.  Ignored\n");
       else {
         qh RANDOMfactor= qh_strtod(s, &s);
         qh_option("Random_perturb", NULL, &qh RANDOMfactor);
         qh RANDOMdist= True;
       }
       break;
     case 'V':
       if (!isdigit(*s) && *s != '-')
         qh_fprintf(qh ferr, 7008, "qhull warning: missing visible distance for option 'Vn'.  Ignored\n");
       else {
         qh MINvisible= qh_strtod(s, &s);
         qh_option("Visible", NULL, &qh MINvisible);
       }
       break;
     case 'U':
       if (!isdigit(*s) && *s != '-')
         qh_fprintf(qh ferr, 7009, "qhull warning: missing coplanar distance for option 'Un'.  Ignored\n");
       else {
         qh MAXcoplanar= qh_strtod(s, &s);
         qh_option("U-coplanar", NULL, &qh MAXcoplanar);
       }
       break;
     case 'W':
       if (*s == '-')
         qh_fprintf(qh ferr, 7010, "qhull warning: negative outside width for option 'Wn'.  Ignored.\n");
       else if (!isdigit(*s))
         qh_fprintf(qh ferr, 7011, "qhull warning: missing outside width for option 'Wn'.  Ignored\n");
       else {
         qh MINoutside= qh_strtod(s, &s);
         qh_option("W-outside", NULL, &qh MINoutside);
         qh APPROXhull= True;
       }
       break;
     /************  sub menus ***************/
     case 'F':
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'a':
           qh_option("Farea", NULL, NULL);
           qh_appendprint(qh_PRINTarea);
           qh GETarea= True;
           break;
         case 'A':
           qh_option("FArea-total", NULL, NULL);
           qh GETarea= True;
           break;
         case 'c':
           qh_option("Fcoplanars", NULL, NULL);
           qh_appendprint(qh_PRINTcoplanars);
           break;
         case 'C':
           qh_option("FCentrums", NULL, NULL);
           qh_appendprint(qh_PRINTcentrums);
           break;
         case 'd':
           qh_option("Fd-cdd-in", NULL, NULL);
           qh CDDinput= True;
           break;
         case 'D':
           qh_option("FD-cdd-out", NULL, NULL);
           qh CDDoutput= True;
           break;
         case 'F':
           qh_option("FFacets-xridge", NULL, NULL);
           qh_appendprint(qh_PRINTfacets_xridge);
           break;
         case 'i':
           qh_option("Finner", NULL, NULL);
           qh_appendprint(qh_PRINTinner);
           break;
         case 'I':
           qh_option("FIDs", NULL, NULL);
           qh_appendprint(qh_PRINTids);
           break;
         case 'm':
           qh_option("Fmerges", NULL, NULL);
           qh_appendprint(qh_PRINTmerges);
           break;
         case 'M':
           qh_option("FMaple", NULL, NULL);
           qh_appendprint(qh_PRINTmaple);
           break;
         case 'n':
           qh_option("Fneighbors", NULL, NULL);
           qh_appendprint(qh_PRINTneighbors);
           break;
         case 'N':
           qh_option("FNeighbors-vertex", NULL, NULL);
           qh_appendprint(qh_PRINTvneighbors);
           break;
         case 'o':
           qh_option("Fouter", NULL, NULL);
           qh_appendprint(qh_PRINTouter);
           break;
         case 'O':
           if (qh PRINToptions1st) {
             qh_option("FOptions", NULL, NULL);
             qh_appendprint(qh_PRINToptions);
           }else
             qh PRINToptions1st= True;
           break;
         case 'p':
           qh_option("Fpoint-intersect", NULL, NULL);
           qh_appendprint(qh_PRINTpointintersect);
           break;
         case 'P':
           qh_option("FPoint-nearest", NULL, NULL);
           qh_appendprint(qh_PRINTpointnearest);
           break;
         case 'Q':
           qh_option("FQhull", NULL, NULL);
           qh_appendprint(qh_PRINTqhull);
           break;
         case 's':
           qh_option("Fsummary", NULL, NULL);
           qh_appendprint(qh_PRINTsummary);
           break;
         case 'S':
           qh_option("FSize", NULL, NULL);
           qh_appendprint(qh_PRINTsize);
           qh GETarea= True;
           break;
         case 't':
           qh_option("Ftriangles", NULL, NULL);
           qh_appendprint(qh_PRINTtriangles);
           break;
         case 'v':
           /* option set in qh_initqhull_globals */
           qh_appendprint(qh_PRINTvertices);
           break;
         case 'V':
           qh_option("FVertex-average", NULL, NULL);
           qh_appendprint(qh_PRINTaverage);
           break;
         case 'x':
           qh_option("Fxtremes", NULL, NULL);
           qh_appendprint(qh_PRINTextremes);
           break;
         default:
           s--;
           qh_fprintf(qh ferr, 7012, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'G':
       isgeom= True;
       qh_appendprint(qh_PRINTgeom);
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'a':
           qh_option("Gall-points", NULL, NULL);
           qh PRINTdots= True;
           break;
         case 'c':
           qh_option("Gcentrums", NULL, NULL);
           qh PRINTcentrums= True;
           break;
         case 'h':
           qh_option("Gintersections", NULL, NULL);
           qh DOintersections= True;
           break;
         case 'i':
           qh_option("Ginner", NULL, NULL);
           qh PRINTinner= True;
           break;
         case 'n':
           qh_option("Gno-planes", NULL, NULL);
           qh PRINTnoplanes= True;
           break;
         case 'o':
           qh_option("Gouter", NULL, NULL);
           qh PRINTouter= True;
           break;
         case 'p':
           qh_option("Gpoints", NULL, NULL);
           qh PRINTcoplanar= True;
           break;
         case 'r':
           qh_option("Gridges", NULL, NULL);
           qh PRINTridges= True;
           break;
         case 't':
           qh_option("Gtransparent", NULL, NULL);
           qh PRINTtransparent= True;
           break;
         case 'v':
           qh_option("Gvertices", NULL, NULL);
           qh PRINTspheres= True;
           break;
         case 'D':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 6035, "qhull input error: missing dimension for option 'GDn'\n");
           else {
             if (qh DROPdim >= 0)
               qh_fprintf(qh ferr, 7013, "qhull warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
                    qh DROPdim);
             qh DROPdim= qh_strtol(s, &s);
             qh_option("GDrop-dim", &qh DROPdim, NULL);
           }
           break;
         default:
           s--;
           qh_fprintf(qh ferr, 7014, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'P':
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'd': case 'D':  /* see qh_initthresholds() */
           key= s[-1];
           i= qh_strtol(s, &s);
           r= 0;
           if (*s == ':') {
             s++;
             r= qh_strtod(s, &s);
           }
           if (key == 'd')
             qh_option("Pdrop-facets-dim-less", &i, &r);
           else
             qh_option("PDrop-facets-dim-more", &i, &r);
           break;
         case 'g':
           qh_option("Pgood-facets", NULL, NULL);
           qh PRINTgood= True;
           break;
         case 'G':
           qh_option("PGood-facet-neighbors", NULL, NULL);
           qh PRINTneighbors= True;
           break;
         case 'o':
           qh_option("Poutput-forced", NULL, NULL);
           qh FORCEoutput= True;
           break;
         case 'p':
           qh_option("Pprecision-ignore", NULL, NULL);
           qh PRINTprecision= False;
           break;
         case 'A':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 6036, "qhull input error: missing facet count for keep area option 'PAn'\n");
           else {
             qh KEEParea= qh_strtol(s, &s);
             qh_option("PArea-keep", &qh KEEParea, NULL);
             qh GETarea= True;
           }
           break;
         case 'F':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 6037, "qhull input error: missing facet area for option 'PFn'\n");
           else {
             qh KEEPminArea= qh_strtod(s, &s);
             qh_option("PFacet-area-keep", NULL, &qh KEEPminArea);
             qh GETarea= True;
           }
           break;
         case 'M':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 6038, "qhull input error: missing merge count for option 'PMn'\n");
           else {
             qh KEEPmerge= qh_strtol(s, &s);
             qh_option("PMerge-keep", &qh KEEPmerge, NULL);
           }
           break;
         default:
           s--;
           qh_fprintf(qh ferr, 7015, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'Q':
       lastproject= -1;
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'b': case 'B':  /* handled by qh_initthresholds */
           key= s[-1];
           if (key == 'b' && *s == 'B') {
             s++;
             r= qh_DEFAULTbox;
             qh SCALEinput= True;
             qh_option("QbBound-unit-box", NULL, &r);
             break;
           }
           if (key == 'b' && *s == 'b') {
             s++;
             qh SCALElast= True;
             qh_option("Qbbound-last", NULL, NULL);
             break;
           }
           k= qh_strtol(s, &s);
           r= 0.0;
           wasproject= False;
           if (*s == ':') {
             s++;
             if ((r= qh_strtod(s, &s)) == 0.0) {
               t= s;            /* need true dimension for memory allocation */
               while (*t && !isspace(*t)) {
                 if (toupper(*t++) == 'B'
                  && k == qh_strtol(t, &t)
                  && *t++ == ':'
                  && qh_strtod(t, &t) == 0.0) {
                   qh PROJECTinput++;
                   trace2((qh ferr, 2004, "qh_initflags: project dimension %d\n", k));
                   qh_option("Qb-project-dim", &k, NULL);
                   wasproject= True;
                   lastproject= k;
                   break;
                 }
               }
             }
           }
           if (!wasproject) {
             if (lastproject == k && r == 0.0)
               lastproject= -1;  /* doesn't catch all possible sequences */
             else if (key == 'b') {
               qh SCALEinput= True;
               if (r == 0.0)
                 r= -qh_DEFAULTbox;
               qh_option("Qbound-dim-low", &k, &r);
             }else {
               qh SCALEinput= True;
               if (r == 0.0)
                 r= qh_DEFAULTbox;
               qh_option("QBound-dim-high", &k, &r);
             }
           }
           break;
         case 'c':
           qh_option("Qcoplanar-keep", NULL, NULL);
           qh KEEPcoplanar= True;
           break;
         case 'f':
           qh_option("Qfurthest-outside", NULL, NULL);
           qh BESToutside= True;
           break;
         case 'g':
           qh_option("Qgood-facets-only", NULL, NULL);
           qh ONLYgood= True;
           break;
         case 'i':
           qh_option("Qinterior-keep", NULL, NULL);
           qh KEEPinside= True;
           break;
         case 'm':
           qh_option("Qmax-outside-only", NULL, NULL);
           qh ONLYmax= True;
           break;
         case 'r':
           qh_option("Qrandom-outside", NULL, NULL);
           qh RANDOMoutside= True;
           break;
         case 's':
           qh_option("Qsearch-initial-simplex", NULL, NULL);
           qh ALLpoints= True;
           break;
         case 't':
           qh_option("Qtriangulate", NULL, NULL);
           qh TRIangulate= True;
           break;
         case 'T':
           qh_option("QTestPoints", NULL, NULL);
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 6039, "qhull input error: missing number of test points for option 'QTn'\n");
           else {
             qh TESTpoints= qh_strtol(s, &s);
             qh_option("QTestPoints", &qh TESTpoints, NULL);
           }
           break;
         case 'u':
           qh_option("QupperDelaunay", NULL, NULL);
           qh UPPERdelaunay= True;
           break;
         case 'v':
           qh_option("Qvertex-neighbors-convex", NULL, NULL);
           qh TESTvneighbors= True;
           break;
         case 'x':
           qh_option("Qxact-merge", NULL, NULL);
           qh MERGEexact= True;
           break;
         case 'z':
           qh_option("Qz-infinity-point", NULL, NULL);
           qh ATinfinity= True;
           break;
         case '0':
           qh_option("Q0-no-premerge", NULL, NULL);
           qh NOpremerge= True;
           break;
         case '1':
           if (!isdigit(*s)) {
             qh_option("Q1-no-angle-sort", NULL, NULL);
             qh ANGLEmerge= False;
             break;
           }
           switch (*s++) {
           case '0':
             qh_option("Q10-no-narrow", NULL, NULL);
             qh NOnarrow= True;
             break;
           case '1':
             qh_option("Q11-trinormals Qtriangulate", NULL, NULL);
             qh TRInormals= True;
             qh TRIangulate= True;
             break;
           default:
             s--;
             qh_fprintf(qh ferr, 7016, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);
             while (*++s && !isspace(*s));
             break;
           }
           break;
         case '2':
           qh_option("Q2-no-merge-independent", NULL, NULL);
           qh MERGEindependent= False;
           goto LABELcheckdigit;
           break; /* no warnings */
         case '3':
           qh_option("Q3-no-merge-vertices", NULL, NULL);
           qh MERGEvertices= False;
         LABELcheckdigit:
           if (isdigit(*s))
             qh_fprintf(qh ferr, 7017, "qhull warning: can not follow '1', '2', or '3' with a digit.  '%c' skipped.\n",
                      *s++);
           break;
         case '4':
           qh_option("Q4-avoid-old-into-new", NULL, NULL);
           qh AVOIDold= True;
           break;
         case '5':
           qh_option("Q5-no-check-outer", NULL, NULL);
           qh SKIPcheckmax= True;
           break;
         case '6':
           qh_option("Q6-no-concave-merge", NULL, NULL);
           qh SKIPconvex= True;
           break;
         case '7':
           qh_option("Q7-no-breadth-first", NULL, NULL);
           qh VIRTUALmemory= True;
           break;
         case '8':
           qh_option("Q8-no-near-inside", NULL, NULL);
           qh NOnearinside= True;
           break;
         case '9':
           qh_option("Q9-pick-furthest", NULL, NULL);
           qh PICKfurthest= True;
           break;
         case 'G':
           i= qh_strtol(s, &t);
           if (qh GOODpoint)
             qh_fprintf(qh ferr, 7018, "qhull warning: good point already defined for option 'QGn'.  Ignored\n");
           else if (s == t)
             qh_fprintf(qh ferr, 7019, "qhull warning: missing good point id for option 'QGn'.  Ignored\n");
           else if (i < 0 || *s == '-') {
             qh GOODpoint= i-1;
             qh_option("QGood-if-dont-see-point", &i, NULL);
           }else {
             qh GOODpoint= i+1;
             qh_option("QGood-if-see-point", &i, NULL);
           }
           s= t;
           break;
         case 'J':
           if (!isdigit(*s) && *s != '-')
             qh JOGGLEmax= 0.0;
           else {
             qh JOGGLEmax= (realT) qh_strtod(s, &s);
             qh_option("QJoggle", NULL, &qh JOGGLEmax);
           }
           break;
         case 'R':
           if (!isdigit(*s) && *s != '-')
             qh_fprintf(qh ferr, 7020, "qhull warning: missing random seed for option 'QRn'.  Ignored\n");
           else {
             qh ROTATErandom= i= qh_strtol(s, &s);
             if (i > 0)
               qh_option("QRotate-id", &i, NULL );
             else if (i < -1)
               qh_option("QRandom-seed", &i, NULL );
           }
           break;
         case 'V':
           i= qh_strtol(s, &t);
           if (qh GOODvertex)
             qh_fprintf(qh ferr, 7021, "qhull warning: good vertex already defined for option 'QVn'.  Ignored\n");
           else if (s == t)
             qh_fprintf(qh ferr, 7022, "qhull warning: no good point id given for option 'QVn'.  Ignored\n");
           else if (i < 0) {
             qh GOODvertex= i - 1;
             qh_option("QV-good-facets-not-point", &i, NULL);
           }else {
             qh_option("QV-good-facets-point", &i, NULL);
             qh GOODvertex= i + 1;
           }
           s= t;
           break;
         default:
           s--;
           qh_fprintf(qh ferr, 7023, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'T':
       while (*s && !isspace(*s)) {
         if (isdigit(*s) || *s == '-')
           qh IStracing= qh_strtol(s, &s);
         else switch (*s++) {
         case 'a':
           qh_option("Tannotate-output", NULL, NULL);
           qh ANNOTATEoutput= True;
           break;
         case 'c':
           qh_option("Tcheck-frequently", NULL, NULL);
           qh CHECKfrequently= True;
           break;
         case 's':
           qh_option("Tstatistics", NULL, NULL);
           qh PRINTstatistics= True;
           break;
         case 'v':
           qh_option("Tverify", NULL, NULL);
           qh VERIFYoutput= True;
           break;
         case 'z':
           if (qh ferr == qh_FILEstderr) {
             /* The C++ interface captures the output in qh_fprint_qhull() */
             qh_option("Tz-stdout", NULL, NULL);
             qh USEstdout= True;
           }else if (!qh fout)
             qh_fprintf(qh ferr, 7024, "qhull warning: output file undefined(stdout).  Option 'Tz' ignored.\n");
           else {
             qh_option("Tz-stdout", NULL, NULL);
             qh USEstdout= True;
             qh ferr= qh fout;
             qhmem.ferr= qh fout;
           }
           break;
         case 'C':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 7025, "qhull warning: missing point id for cone for trace option 'TCn'.  Ignored\n");
           else {
             i= qh_strtol(s, &s);
             qh_option("TCone-stop", &i, NULL);
             qh STOPcone= i + 1;
           }
           break;
         case 'F':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 7026, "qhull warning: missing frequency count for trace option 'TFn'.  Ignored\n");
           else {
             qh REPORTfreq= qh_strtol(s, &s);
             qh_option("TFacet-log", &qh REPORTfreq, NULL);
             qh REPORTfreq2= qh REPORTfreq/2;  /* for tracemerging() */
           }
           break;
         case 'I':
           if (!isspace(*s))
             qh_fprintf(qh ferr, 7027, "qhull warning: missing space between 'TI' and filename, %s\n", s);
           while (isspace(*s))
             s++;
           t= qh_skipfilename(s);
           {
             char filename[qh_FILENAMElen];
 
             qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s));   /* WARN64 */
             s= t;
             if (!freopen(filename, "r", stdin)) {
               qh_fprintf(qh ferr, 6041, "qhull error: could not open file \"%s\".", filename);
               qh_errexit(qh_ERRinput, NULL, NULL);
             }else {
               qh_option("TInput-file", NULL, NULL);
               qh_option(filename, NULL, NULL);
             }
           }
           break;
         case 'O':
             if (!isspace(*s))
                 qh_fprintf(qh ferr, 7028, "qhull warning: missing space between 'TO' and filename, %s\n", s);
             while (isspace(*s))
                 s++;
             t= qh_skipfilename(s);
             {
               char filename[qh_FILENAMElen];
 
               qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s));  /* WARN64 */
               s= t;
               if (!freopen(filename, "w", stdout)) {
                 qh_fprintf(qh ferr, 6044, "qhull error: could not open file \"%s\".", filename);
                 qh_errexit(qh_ERRinput, NULL, NULL);
               }else {
                 qh_option("TOutput-file", NULL, NULL);
               qh_option(filename, NULL, NULL);
             }
           }
           break;
         case 'P':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 7029, "qhull warning: missing point id for trace option 'TPn'.  Ignored\n");
           else {
             qh TRACEpoint= qh_strtol(s, &s);
             qh_option("Trace-point", &qh TRACEpoint, NULL);
           }
           break;
         case 'M':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 7030, "qhull warning: missing merge id for trace option 'TMn'.  Ignored\n");
           else {
             qh TRACEmerge= qh_strtol(s, &s);
             qh_option("Trace-merge", &qh TRACEmerge, NULL);
           }
           break;
         case 'R':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 7031, "qhull warning: missing rerun count for trace option 'TRn'.  Ignored\n");
           else {
             qh RERUN= qh_strtol(s, &s);
             qh_option("TRerun", &qh RERUN, NULL);
           }
           break;
         case 'V':
           i= qh_strtol(s, &t);
           if (s == t)
             qh_fprintf(qh ferr, 7032, "qhull warning: missing furthest point id for trace option 'TVn'.  Ignored\n");
           else if (i < 0) {
             qh STOPpoint= i - 1;
             qh_option("TV-stop-before-point", &i, NULL);
           }else {
             qh STOPpoint= i + 1;
             qh_option("TV-stop-after-point", &i, NULL);
           }
           s= t;
           break;
         case 'W':
           if (!isdigit(*s))
             qh_fprintf(qh ferr, 7033, "qhull warning: missing max width for trace option 'TWn'.  Ignored\n");
           else {
             qh TRACEdist= (realT) qh_strtod(s, &s);
             qh_option("TWide-trace", NULL, &qh TRACEdist);
           }
           break;
         default:
           s--;
           qh_fprintf(qh ferr, 7034, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     default:
       qh_fprintf(qh ferr, 7035, "qhull warning: unknown flag %c(%x)\n", (int)s[-1],
                (int)s[-1]);
       break;
     }
     if (s-1 == prev_s && *s && !isspace(*s)) {
       qh_fprintf(qh ferr, 7036, "qhull warning: missing space after flag %c(%x); reserved for menu. Skipped.\n",
                (int)*prev_s, (int)*prev_s);
       while (*s && !isspace(*s))
         s++;
     }
   }
   if (qh STOPcone && qh JOGGLEmax < REALmax/2)
     qh_fprintf(qh ferr, 7078, "qhull warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");
   if (isgeom && !qh FORCEoutput && qh PRINTout[1])
     qh_fprintf(qh ferr, 7037, "qhull warning: additional output formats are not compatible with Geomview\n");
   /* set derived values in qh_initqhull_globals */
 } /* initflags */
 
 
 /*---------------------------------
 
   qh_initqhull_buffers()
     initialize global memory buffers
 
   notes:
     must match qh_freebuffers()
 */
 void qh_initqhull_buffers(void) {
   int k;
 
   qh TEMPsize= (qhmem.LASTsize - sizeof(setT))/SETelemsize;
   if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize)
     qh TEMPsize= 8;  /* e.g., if qh_NOmem */
   qh other_points= qh_setnew(qh TEMPsize);
   qh del_vertices= qh_setnew(qh TEMPsize);
   qh coplanarfacetset= qh_setnew(qh TEMPsize);
   qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT));
   qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
   qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
   qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
   qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
   for (k=qh input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_ouputflags */
     qh lower_threshold[k]= -REALmax;
     qh upper_threshold[k]= REALmax;
     qh lower_bound[k]= -REALmax;
     qh upper_bound[k]= REALmax;
   }
   qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT));
   qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *));
 } /* initqhull_buffers */
 
 /*---------------------------------
 
   qh_initqhull_globals( points, numpoints, dim, ismalloc )
     initialize globals
     if ismalloc
       points were malloc'd and qhull should free at end
 
   returns:
     sets qh.first_point, num_points, input_dim, hull_dim and others
     seeds random number generator (seed=1 if tracing)
     modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
     adjust user flags as needed
     also checks DIM3 dependencies and constants
 
   notes:
     do not use qh_point() since an input transformation may move them elsewhere
 
   see:
     qh_initqhull_start() sets default values for non-zero globals
 
   design:
     initialize points array from input arguments
     test for qh.ZEROcentrum
       (i.e., use opposite vertex instead of cetrum for convexity testing)
     initialize qh.CENTERtype, qh.normal_size,
       qh.center_size, qh.TRACEpoint/level,
     initialize and test random numbers
     qh_initqhull_outputflags() -- adjust and test output flags
 */
 void qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc) {
   int seed, pointsneeded, extra= 0, i, randi, k;
   realT randr;
   realT factorial;
 
   time_t timedata;
 
   trace0((qh ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh rbox_command,
       qh qhull_command));
   qh POINTSmalloc= ismalloc;
   qh first_point= points;
   qh num_points= numpoints;
   qh hull_dim= qh input_dim= dim;
   if (!qh NOpremerge && !qh MERGEexact && !qh PREmerge && qh JOGGLEmax > REALmax/2) {
     qh MERGING= True;
     if (qh hull_dim <= 4) {
       qh PREmerge= True;
       qh_option("_pre-merge", NULL, NULL);
     }else {
       qh MERGEexact= True;
       qh_option("Qxact_merge", NULL, NULL);
     }
   }else if (qh MERGEexact)
     qh MERGING= True;
   if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) {
 #ifdef qh_NOmerge
     qh JOGGLEmax= 0.0;
 #endif
   }
   if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && qh PRINTprecision)
     qh_fprintf(qh ferr, 7038, "qhull warning: joggle('QJ') always produces simplicial output.  Triangulated output('Qt') does nothing.\n");
   if (qh JOGGLEmax < REALmax/2 && qh DELAUNAY && !qh SCALEinput && !qh SCALElast) {
     qh SCALElast= True;
     qh_option("Qbbound-last-qj", NULL, NULL);
   }
   if (qh MERGING && !qh POSTmerge && qh premerge_cos > REALmax/2
   && qh premerge_centrum == 0) {
     qh ZEROcentrum= True;
     qh ZEROall_ok= True;
     qh_option("_zero-centrum", NULL, NULL);
   }
   if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision)
     qh_fprintf(qh ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user.h).\n",
           REALepsilon);
 #ifdef qh_NOmerge
   if (qh MERGING) {
     qh_fprintf(qh ferr, 6045, "qhull input error: merging not installed(qh_NOmerge + 'Qx', 'Cn' or 'An')\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
 #endif
   if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) {
     qh KEEPinside= True;
     qh_option("Qinterior-keep", NULL, NULL);
   }
   if (qh DELAUNAY && qh HALFspace) {
     qh_fprintf(qh ferr, 6046, "qhull input error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) {
     qh_fprintf(qh ferr, 6047, "qhull input error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (qh UPPERdelaunay && qh ATinfinity) {
     qh_fprintf(qh ferr, 6048, "qhull input error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision)
     qh_fprintf(qh ferr, 7040, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
   qh DOcheckmax= (!qh SKIPcheckmax && qh MERGING );
   qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar)
                           && !qh NOnearinside);
   if (qh MERGING)
     qh CENTERtype= qh_AScentrum;
   else if (qh VORONOI)
     qh CENTERtype= qh_ASvoronoi;
   if (qh TESTvneighbors && !qh MERGING) {
     qh_fprintf(qh ferr, 6049, "qhull input error: test vertex neighbors('Qv') needs a merge option\n");
     qh_errexit(qh_ERRinput, NULL ,NULL);
   }
   if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) {
     qh hull_dim -= qh PROJECTinput;
     if (qh DELAUNAY) {
       qh hull_dim++;
       if (qh ATinfinity)
         extra= 1;
     }
   }
   if (qh hull_dim <= 1) {
     qh_fprintf(qh ferr, 6050, "qhull error: dimension %d must be > 1\n", qh hull_dim);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   for (k=2, factorial=1.0; k < qh hull_dim; k++)
     factorial *= k;
   qh AREAfactor= 1.0 / factorial;
   trace2((qh ferr, 2005, "qh_initqhull_globals: initialize globals.  dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n",
         dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim));
   qh normal_size= qh hull_dim * sizeof(coordT);
   qh center_size= qh normal_size - sizeof(coordT);
   pointsneeded= qh hull_dim+1;
   if (qh hull_dim > qh_DIMmergeVertex) {
     qh MERGEvertices= False;
     qh_option("Q3-no-merge-vertices-dim-high", NULL, NULL);
   }
   if (qh GOODpoint)
     pointsneeded++;
 #ifdef qh_NOtrace
   if (qh IStracing) {
     qh_fprintf(qh ferr, 6051, "qhull input error: tracing is not installed(qh_NOtrace in user.h)");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
 #endif
   if (qh RERUN > 1) {
     qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */
     if (qh IStracing != -1)
       qh IStracing= 0;
   }else if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
     qh TRACElevel= (qh IStracing? qh IStracing : 3);
     qh IStracing= 0;
   }
   if (qh ROTATErandom == 0 || qh ROTATErandom == -1) {
     seed= (int)time(&timedata);
     if (qh ROTATErandom  == -1) {
       seed= -seed;
       qh_option("QRandom-seed", &seed, NULL );
     }else
       qh_option("QRotate-random", &seed, NULL);
     qh ROTATErandom= seed;
   }
   seed= qh ROTATErandom;
   if (seed == INT_MIN)    /* default value */
     seed= 1;
   else if (seed < 0)
     seed= -seed;
   qh_RANDOMseed_(seed);
   randr= 0.0;
   for (i=1000; i--; ) {
     randi= qh_RANDOMint;
     randr += randi;
     if (randi > qh_RANDOMmax) {
       qh_fprintf(qh ferr, 8036, "\
 qhull configuration error (qh_RANDOMmax in user.h):\n\
    random integer %d > qh_RANDOMmax(%.8g)\n",
                randi, qh_RANDOMmax);
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
   }
   qh_RANDOMseed_(seed);
   randr = randr/1000;
   if (randr < qh_RANDOMmax * 0.1
   || randr > qh_RANDOMmax * 0.9)
     qh_fprintf(qh ferr, 8037, "\
 qhull configuration warning (qh_RANDOMmax in user.h):\n\
    average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\
    Is qh_RANDOMmax (%.2g) wrong?\n",
              randr, qh_RANDOMmax * 0.5, qh_RANDOMmax);
   qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
   qh RANDOMb= 1.0 - qh RANDOMfactor;
   if (qh_HASHfactor < 1.1) {
     qh_fprintf(qh ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
       qh_HASHfactor);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   if (numpoints+extra < pointsneeded) {
     qh_fprintf(qh ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",
             numpoints, pointsneeded);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   qh_initqhull_outputflags();
 } /* initqhull_globals */
 
 /*---------------------------------
 
   qh_initqhull_mem(  )
     initialize mem.c for qhull
     qh.hull_dim and qh.normal_size determine some of the allocation sizes
     if qh.MERGING,
       includes ridgeT
     calls qh_user_memsizes() to add up to 10 additional sizes for quick allocation
       (see numsizes below)
 
   returns:
     mem.c already for qh_memalloc/qh_memfree (errors if called beforehand)
 
   notes:
     qh_produceoutput() prints memsizes
 
 */
 void qh_initqhull_mem(void) {
   int numsizes;
   int i;
 
   numsizes= 8+10;
   qh_meminitbuffers(qh IStracing, qh_MEMalign, numsizes,
                      qh_MEMbufsize,qh_MEMinitbuf);
   qh_memsize((int)sizeof(vertexT));
   if (qh MERGING) {
     qh_memsize((int)sizeof(ridgeT));
     qh_memsize((int)sizeof(mergeT));
   }
   qh_memsize((int)sizeof(facetT));
   i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;  /* ridge.vertices */
   qh_memsize(i);
   qh_memsize(qh normal_size);        /* normal */
   i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
   qh_memsize(i);
   qh_user_memsizes();
   qh_memsetup();
 } /* initqhull_mem */
 
 /*---------------------------------
 
   qh_initqhull_outputflags
     initialize flags concerned with output
 
   returns:
     adjust user flags as needed
 
   see:
     qh_clear_outputflags() resets the flags
 
   design:
     test for qh.PRINTgood (i.e., only print 'good' facets)
     check for conflicting print output options
 */
 void qh_initqhull_outputflags(void) {
   boolT printgeom= False, printmath= False, printcoplanar= False;
   int i;
 
   trace3((qh ferr, 3024, "qh_initqhull_outputflags: %s\n", qh qhull_command));
   if (!(qh PRINTgood || qh PRINTneighbors)) {
     if (qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge || qh DELAUNAY
         || (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) {
       qh PRINTgood= True;
       qh_option("Pgood", NULL, NULL);
     }
   }
   if (qh PRINTtransparent) {
     if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) {
       qh_fprintf(qh ferr, 6215, "qhull input error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     qh DROPdim = 3;
     qh PRINTridges = True;
   }
   for (i=qh_PRINTEND; i--; ) {
     if (qh PRINTout[i] == qh_PRINTgeom)
       printgeom= True;
     else if (qh PRINTout[i] == qh_PRINTmathematica || qh PRINTout[i] == qh_PRINTmaple)
       printmath= True;
     else if (qh PRINTout[i] == qh_PRINTcoplanars)
       printcoplanar= True;
     else if (qh PRINTout[i] == qh_PRINTpointnearest)
       printcoplanar= True;
     else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) {
       qh_fprintf(qh ferr, 6053, "qhull input error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) {
       qh_fprintf(qh ferr, 6054, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) {
       qh_fprintf(qh ferr, 6055, "qhull input error: option 'FC' is not available for Voronoi vertices('v')\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }else if (qh PRINTout[i] == qh_PRINTvertices) {
       if (qh VORONOI)
         qh_option("Fvoronoi", NULL, NULL);
       else
         qh_option("Fvertices", NULL, NULL);
     }
   }
   if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) {
     if (qh PRINTprecision)
       qh_fprintf(qh ferr, 7041, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
   }
   if (printmath && (qh hull_dim > 3 || qh VORONOI)) {
     qh_fprintf(qh ferr, 6056, "qhull input error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (printgeom) {
     if (qh hull_dim > 4) {
       qh_fprintf(qh ferr, 6057, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums
      + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) {
       qh_fprintf(qh ferr, 6058, "qhull input error: no output specified for Geomview\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) {
       qh_fprintf(qh ferr, 6059, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     /* can not warn about furthest-site Geomview output: no lower_threshold */
     if (qh hull_dim == 4 && qh DROPdim == -1 &&
         (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
       qh_fprintf(qh ferr, 7042, "qhull input warning: coplanars, vertices, and centrums output not\n\
 available for 4-d output(ignored).  Could use 'GDn' instead.\n");
       qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False;
     }
   }
   if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) {
     if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) {
       if (qh QHULLfinished) {
         qh_fprintf(qh ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");
       }else {
         qh KEEPcoplanar = True;
         qh_option("Qcoplanar", NULL, NULL);
       }
     }
   }
   qh PRINTdim= qh hull_dim;
   if (qh DROPdim >=0) {    /* after Geomview checks */
     if (qh DROPdim < qh hull_dim) {
       qh PRINTdim--;
       if (!printgeom || qh hull_dim < 3)
         qh_fprintf(qh ferr, 7043, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim);
     }else
       qh DROPdim= -1;
   }else if (qh VORONOI) {
     qh DROPdim= qh hull_dim-1;
     qh PRINTdim= qh hull_dim-1;
   }
 } /* qh_initqhull_outputflags */
 
 /*---------------------------------
 
   qh_initqhull_start( infile, outfile, errfile )
     allocate memory if needed and call qh_initqhull_start2()
 */
 void qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile) {
 
 #if qh_QHpointer
   if (qh_qh) {
     qh_fprintf(errfile, 6205, "qhull error (qh_initqhull_start): qh_qh already defined.  Call qh_save_qhull() first\n");
     qh_exit(qh_ERRqhull);  /* no error handler */
   }
   if (!(qh_qh= (qhT *)qh_malloc(sizeof(qhT)))) {
     qh_fprintf(errfile, 6060, "qhull error (qh_initqhull_start): insufficient memory\n");
     qh_exit(qh_ERRmem);  /* no error handler */
   }
 #endif
   qh_initstatistics();
   qh_initqhull_start2(infile, outfile, errfile);
 } /* initqhull_start */
 
 /*---------------------------------
 
   qh_initqhull_start2( infile, outfile, errfile )
     start initialization of qhull
     initialize statistics, stdio, default values for global variables
     assumes qh_qh is defined
   notes:
     report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized
   see:
     qh_maxmin() determines the precision constants
     qh_freeqhull2()
 */
 void qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile) {
   time_t timedata;
   int seed;
 
   qh_CPUclock; /* start the clock(for qh_clock).  One-shot. */
 #if qh_QHpointer
   memset((char *)qh_qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
 #else
   memset((char *)&qh_qh, 0, sizeof(qhT));
 #endif
   qh ANGLEmerge= True;
   qh DROPdim= -1;
   qh ferr= errfile;
   qh fin= infile;
   qh fout= outfile;
   qh furthest_id= -1;
   qh JOGGLEmax= REALmax;
   qh KEEPminArea = REALmax;
   qh last_low= REALmax;
   qh last_high= REALmax;
   qh last_newhigh= REALmax;
   qh max_outside= 0.0;
   qh max_vertex= 0.0;
   qh MAXabs_coord= 0.0;
   qh MAXsumcoord= 0.0;
   qh MAXwidth= -REALmax;
   qh MERGEindependent= True;
   qh MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */
   qh MINoutside= 0.0;
   qh MINvisible= REALmax;
   qh MAXcoplanar= REALmax;
   qh outside_err= REALmax;
   qh premerge_centrum= 0.0;
   qh premerge_cos= REALmax;
   qh PRINTprecision= True;
   qh PRINTradius= 0.0;
   qh postmerge_cos= REALmax;
   qh postmerge_centrum= 0.0;
   qh ROTATErandom= INT_MIN;
   qh MERGEvertices= True;
   qh totarea= 0.0;
   qh totvol= 0.0;
   qh TRACEdist= REALmax;
   qh TRACEpoint= -1; /* recompile or use 'TPn' */
   qh tracefacet_id= UINT_MAX;  /* recompile to trace a facet */
   qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex */
   seed= (int)time(&timedata);
   qh_RANDOMseed_(seed);
   qh->run_id= qh_RANDOMint;
   if(!qh->run_id)
       qh->run_id++;  /* guarantee non-zero */
   qh_option("run-id", &qh run_id, NULL);
   strcat(qh qhull, "qhull");
 } /* initqhull_start2 */
 
 /*---------------------------------
 
   qh_initthresholds( commandString )
     set thresholds for printing and scaling from commandString
 
   returns:
     sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used
 
   see:
     qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
     qh_inthresholds()
 
   design:
     for each 'Pdn' or 'PDn' option
       check syntax
       set qh.lower_threshold or qh.upper_threshold
     set qh.GOODthreshold if an unbounded threshold is used
     set qh.SPLITthreshold if a bounded threshold is used
 */
 void qh_initthresholds(char *command) {
   realT value;
   int idx, maxdim, k;
   char *s= command; /* non-const due to strtol */
   char key;
 
   maxdim= qh input_dim;
   if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput))
     maxdim++;
   while (*s) {
     if (*s == '-')
       s++;
     if (*s == 'P') {
       s++;
       while (*s && !isspace(key= *s++)) {
         if (key == 'd' || key == 'D') {
           if (!isdigit(*s)) {
             qh_fprintf(qh ferr, 7044, "qhull warning: no dimension given for Print option '%c' at: %s.  Ignored\n",
                     key, s-1);
             continue;
           }
           idx= qh_strtol(s, &s);
           if (idx >= qh hull_dim) {
             qh_fprintf(qh ferr, 7045, "qhull warning: dimension %d for Print option '%c' is >= %d.  Ignored\n",
                 idx, key, qh hull_dim);
             continue;
           }
           if (*s == ':') {
             s++;
             value= qh_strtod(s, &s);
             if (fabs((double)value) > 1.0) {
               qh_fprintf(qh ferr, 7046, "qhull warning: value %2.4g for Print option %c is > +1 or < -1.  Ignored\n",
                       value, key);
               continue;
             }
           }else
             value= 0.0;
           if (key == 'd')
             qh lower_threshold[idx]= value;
           else
             qh upper_threshold[idx]= value;
         }
       }
     }else if (*s == 'Q') {
       s++;
       while (*s && !isspace(key= *s++)) {
         if (key == 'b' && *s == 'B') {
           s++;
           for (k=maxdim; k--; ) {
             qh lower_bound[k]= -qh_DEFAULTbox;
             qh upper_bound[k]= qh_DEFAULTbox;
           }
         }else if (key == 'b' && *s == 'b')
           s++;
         else if (key == 'b' || key == 'B') {
           if (!isdigit(*s)) {
             qh_fprintf(qh ferr, 7047, "qhull warning: no dimension given for Qhull option %c.  Ignored\n",
                     key);
             continue;
           }
           idx= qh_strtol(s, &s);
           if (idx >= maxdim) {
             qh_fprintf(qh ferr, 7048, "qhull warning: dimension %d for Qhull option %c is >= %d.  Ignored\n",
                 idx, key, maxdim);
             continue;
           }
           if (*s == ':') {
             s++;
             value= qh_strtod(s, &s);
           }else if (key == 'b')
             value= -qh_DEFAULTbox;
           else
             value= qh_DEFAULTbox;
           if (key == 'b')
             qh lower_bound[idx]= value;
           else
             qh upper_bound[idx]= value;
         }
       }
     }else {
       while (*s && !isspace(*s))
         s++;
     }
     while (isspace(*s))
       s++;
   }
   for (k=qh hull_dim; k--; ) {
     if (qh lower_threshold[k] > -REALmax/2) {
       qh GOODthreshold= True;
       if (qh upper_threshold[k] < REALmax/2) {
         qh SPLITthresholds= True;
         qh GOODthreshold= False;
         break;
       }
     }else if (qh upper_threshold[k] < REALmax/2)
       qh GOODthreshold= True;
   }
 } /* initthresholds */
 
 /*---------------------------------
 
   qh_option( option, intVal, realVal )
     add an option description to qh.qhull_options
 
   notes:
     NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]
     will be printed with statistics ('Ts') and errors
     strlen(option) < 40
 */
 void qh_option(const char *option, int *i, realT *r) {
   char buf[200];
   int len, maxlen;
 
   sprintf(buf, "  %s", option);
   if (i)
     sprintf(buf+strlen(buf), " %d", *i);
   if (r)
     sprintf(buf+strlen(buf), " %2.2g", *r);
   len= (int)strlen(buf);  /* WARN64 */
   qh qhull_optionlen += len;
   maxlen= sizeof(qh qhull_options) - len -1;
   maximize_(maxlen, 0);
   if (qh qhull_optionlen >= qh_OPTIONline && maxlen > 0) {
     qh qhull_optionlen= len;
     strncat(qh qhull_options, "\n", (size_t)(maxlen--));
   }
   strncat(qh qhull_options, buf, (size_t)maxlen);
 } /* option */
 
 #if qh_QHpointer
 /*---------------------------------
 
   qh_restore_qhull( oldqh )
     restores a previously saved qhull
     also restores qh_qhstat and qhmem.tempstack
     Sets *oldqh to NULL
   notes:
     errors if current qhull hasn't been saved or freed
     uses qhmem for error reporting
 
   NOTE 1998/5/11:
     Freeing memory after qh_save_qhull and qh_restore_qhull
     is complicated.  The procedures will be redesigned.
 
   see:
     qh_save_qhull(), UsingLibQhull
 */
 void qh_restore_qhull(qhT **oldqh) {
 
   if (*oldqh && strcmp((*oldqh)->qhull, "qhull")) {
     qh_fprintf(qhmem.ferr, 6061, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n",
                   *oldqh);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   if (qh_qh) {
     qh_fprintf(qhmem.ferr, 6062, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   if (!*oldqh || !(*oldqh)->old_qhstat) {
     qh_fprintf(qhmem.ferr, 6063, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n",
                   *oldqh);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   qh_qh= *oldqh;
   *oldqh= NULL;
   qh_qhstat= qh old_qhstat;
   qhmem.tempstack= qh old_tempstack;
   qh old_qhstat= 0;
   qh old_tempstack= 0;
   trace1((qh ferr, 1007, "qh_restore_qhull: restored qhull from %p\n", *oldqh));
 } /* restore_qhull */
 
 /*---------------------------------
 
   qh_save_qhull(  )
     saves qhull for a later qh_restore_qhull
     also saves qh_qhstat and qhmem.tempstack
 
   returns:
     qh_qh=NULL
 
   notes:
     need to initialize qhull or call qh_restore_qhull before continuing
 
   NOTE 1998/5/11:
     Freeing memory after qh_save_qhull and qh_restore_qhull
     is complicated.  The procedures will be redesigned.
 
   see:
     qh_restore_qhull()
 */
 qhT *qh_save_qhull(void) {
   qhT *oldqh;
 
   trace1((qhmem.ferr, 1045, "qh_save_qhull: save qhull %p\n", qh_qh));
   if (!qh_qh) {
     qh_fprintf(qhmem.ferr, 6064, "qhull internal error (qh_save_qhull): qhull not initialized\n");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   qh old_qhstat= qh_qhstat;
   qh_qhstat= NULL;
   qh old_tempstack= qhmem.tempstack;
   qhmem.tempstack= NULL;
   oldqh= qh_qh;
   qh_qh= NULL;
   return oldqh;
 } /* save_qhull */
 
 #endif
 
diff --git a/src/libqhull/index.htm b/src/libqhull/index.htm
index b9ca9d0..15f84b8 100644
--- a/src/libqhull/index.htm
+++ b/src/libqhull/index.htm
@@ -1,248 +1,248 @@
 
 
 
 
 Qhull functions, macros, and data structures
 
 
 
 
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


Qhull functions, macros, and data structures

The following sections provide an overview and index to Qhull's functions, macros, and data structures. Each section starts with an introduction. If you use Opera, the source code links back to this documentation. See also Calling Qhull from C programs and Calling Qhull from C++ programs.

Qhull uses the following conventions:

  • in code, global variables start with "qh "
  • in documentation, global variables start with 'qh.'
  • constants start with an upper case word
  • important globals include an '_'
  • functions, macros, and constants start with "qh_"
  • data types end in "T"
  • macros with arguments end in "_"
  • iterators are macros that use local variables
  • iterators for sets start with "FOREACH"
  • iterators for lists start with "FORALL"
  • qhull options are in single quotes (e.g., 'Pdn')
  • lists are sorted alphabetically
  • preprocessor directives on left margin for older compilers

When reading the code, please note that the global data structure, 'qh', is a macro. It either expands to "qh_qh." or to "qh_qh->". The later is used for applications which run concurrent calls to qh_qhull().

When reading code with an editor, a search for "procedure will locate the header of qh_procedure. A search for * procedure will locate the tail of qh_procedure.

A useful starting point is libqhull.h. It defines most of Qhull data structures and top-level functions. Search for 'PFn' to determine the corresponding constant in Qhull. Search for 'Fp' to determine the corresponding qh_PRINT... constant. Search io.c to learn how the print function is implemented.

If your web browser loads .c and .h files with an external application, change the MIME type of .c and .h files to "text/html". Opera does not always work since it treats '<' characters as HTML tags.

Please report documentation and link errors to qhull-bug@qhull.org.

-

Copyright © 1997-2012 C.B. Barber

+

Copyright © 1997-2015 C.B. Barber


»Qhull files

This sections lists the .c and .h files for Qhull. Please refer to these files for detailed information.

Makefile, CMakeLists.txt
Makefile is preconfigured for gcc. CMakeLists.txt supports multiple platforms with CMake. Qhull includes project files for Visual Studio and Qt.
 
libqhull.h
Include file for the Qhull library (libqhull.so, qhull.dll, libqhullstatic.a). Data structures are documented under Poly. Global variables are documented under Global. Other data structures and variables are documented under Qhull or Geom.
 
Geom, geom.h, geom.c, geom2.c, random.c, random.h
Geometric routines. These routines implement mathematical functions such as Gaussian elimination and geometric routines needed for Qhull. Frequently used routines are in geom.c while infrequent ones are in geom2.c.
 
Global, global.c, libqhull.h
Global routines. Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. global.c initializes and frees these structures.
 
Io, io.h, io.c
Input and output routines. Qhull provides a wide range of input and output options.
 
Mem, mem.h, mem.c
Memory routines. Qhull provides memory allocation and deallocation. It uses quick-fit allocation.
 
Merge, merge.h, merge.c
Merge routines. Qhull handles precision problems by merged facets or joggled input. These routines merge simplicial facets, merge non-simplicial facets, merge cycles of facets, and rename redundant vertices.
 
Poly, poly.h, poly.c, poly2.c, libqhull.h
Polyhedral routines. Qhull produces a polyhedron as a list of facets with vertices, neighbors, ridges, and geometric information. libqhull.h defines the main data structures. Frequently used routines are in poly.c while infrequent ones are in poly2.c.
 
Qhull, libqhull.c, libqhull.h, qhull_a.h, unix.c , qconvex.c , qdelaun.c , qhalf.c , qvoronoi.c
Top-level routines. The Quickhull algorithm is implemented by libqhull.c. qhull_a.h includes all header files.
 
Set, qset.h, qset.c
Set routines. Qhull implements its data structures as sets. A set is an array of pointers that is expanded as needed. This is a separate package that may be used in other applications.
 
Stat, stat.h, stat.c
Statistical routines. Qhull maintains statistics about its implementation.
 
User, user.h, user.c, user_eg.c, user_eg2.c, user_eg3.cpp, qhull_interface.cpp
User-defined routines. Qhull allows the user to configure the code with defined constants and specialized routines.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/io.c b/src/libqhull/io.c index 4094463..9094794 100644 --- a/src/libqhull/io.c +++ b/src/libqhull/io.c @@ -1,4062 +1,4062 @@ /*
  ---------------------------------
 
    io.c
    Input/Output routines of qhull application
 
    see qh-io.htm and io.h
 
    see user.c for qh_errprint and qh_printfacetlist
 
    unix.c calls qh_readpoints and qh_produce_output
 
    unix.c and user.c are the only callers of io.c functions
    This allows the user to avoid loading io.o from qhull.a
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/io.c#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/io.c#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_a.h"
 
 /*========= -functions in alphabetical order after qh_produce_output()  =====*/
 
 /*---------------------------------
 
   qh_produce_output()
   qh_produce_output2()
     prints out the result of qhull in desired format
     qh_produce_output2() does not call qh_prepare_output()
     if qh.GETarea
       computes and prints area and volume
     qh.PRINTout[] is an array of output formats
 
   notes:
     prints output in qh.PRINTout order
 */
 void qh_produce_output(void) {
     int tempsize= qh_setsize(qhmem.tempstack);
 
     qh_prepare_output();
     qh_produce_output2();
     if (qh_setsize(qhmem.tempstack) != tempsize) {
         qh_fprintf(qh ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",
             qh_setsize(qhmem.tempstack));
         qh_errexit(qh_ERRqhull, NULL, NULL);
     }
 } /* produce_output */
 
 
 void qh_produce_output2(void) {
   int i, tempsize= qh_setsize(qhmem.tempstack), d_1;
 
   if (qh PRINTsummary)
     qh_printsummary(qh ferr);
   else if (qh PRINTout[0] == qh_PRINTnone)
     qh_printsummary(qh fout);
   for (i=0; i < qh_PRINTEND; i++)
     qh_printfacets(qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
   qh_allstatistics();
   if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
     qh_printstats(qh ferr, qhstat precision, NULL);
   if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
     qh_printstats(qh ferr, qhstat vridges, NULL);
   if (qh PRINTstatistics) {
     qh_printstatistics(qh ferr, "");
     qh_memstatistics(qh ferr);
     d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
     qh_fprintf(qh ferr, 8040, "\
     size in bytes: merge %d ridge %d vertex %d facet %d\n\
          normal %d ridge vertices %d facet vertices or neighbors %d\n",
             (int)sizeof(mergeT), (int)sizeof(ridgeT),
             (int)sizeof(vertexT), (int)sizeof(facetT),
             qh normal_size, d_1, d_1 + SETelemsize);
   }
   if (qh_setsize(qhmem.tempstack) != tempsize) {
     qh_fprintf(qh ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",
              qh_setsize(qhmem.tempstack));
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
 } /* produce_output2 */
 
 /*---------------------------------
 
   qh_dfacet( id )
     print facet by id, for debugging
 
 */
 void qh_dfacet(unsigned id) {
   facetT *facet;
 
   FORALLfacets {
     if (facet->id == id) {
       qh_printfacet(qh fout, facet);
       break;
     }
   }
 } /* qh_dfacet */
 
 
 /*---------------------------------
 
   qh_dvertex( id )
     print vertex by id, for debugging
 */
 void qh_dvertex(unsigned id) {
   vertexT *vertex;
 
   FORALLvertices {
     if (vertex->id == id) {
       qh_printvertex(qh fout, vertex);
       break;
     }
   }
 } /* qh_dvertex */
 
 
 /*---------------------------------
 
   qh_compare_facetarea( p1, p2 )
     used by qsort() to order facets by area
 */
 int qh_compare_facetarea(const void *p1, const void *p2) {
   const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
 
   if (!a->isarea)
     return -1;
   if (!b->isarea)
     return 1;
   if (a->f.area > b->f.area)
     return 1;
   else if (a->f.area == b->f.area)
     return 0;
   return -1;
 } /* compare_facetarea */
 
 /*---------------------------------
 
   qh_compare_facetmerge( p1, p2 )
     used by qsort() to order facets by number of merges
 */
 int qh_compare_facetmerge(const void *p1, const void *p2) {
   const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
 
   return(a->nummerge - b->nummerge);
 } /* compare_facetvisit */
 
 /*---------------------------------
 
   qh_compare_facetvisit( p1, p2 )
     used by qsort() to order facets by visit id or id
 */
 int qh_compare_facetvisit(const void *p1, const void *p2) {
   const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
   int i,j;
 
   if (!(i= a->visitid))
     i= 0 - a->id; /* do not convert to int, sign distinguishes id from visitid */
   if (!(j= b->visitid))
     j= 0 - b->id;
   return(i - j);
 } /* compare_facetvisit */
 
 /*---------------------------------
 
   qh_compare_vertexpoint( p1, p2 )
     used by qsort() to order vertices by point id
 
   Not used.  Not available in libqhull_r.h since qh_pointid depends on qh
 */
 int qh_compare_vertexpoint(const void *p1, const void *p2) {
   const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);
 
   return((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
 } /* compare_vertexpoint */
 
 /*---------------------------------
 
   qh_copyfilename( dest, size, source, length )
     copy filename identified by qh_skipfilename()
 
   notes:
     see qh_skipfilename() for syntax
 */
 void qh_copyfilename(char *filename, int size, const char* source, int length) {
   char c= *source;
 
   if (length > size + 1) {
       qh_fprintf(qh ferr, 6040, "qhull error: filename is more than %d characters, %s\n",  size-1, source);
       qh_errexit(qh_ERRinput, NULL, NULL);
   }
   strncpy(filename, source, length);
   filename[length]= '\0';
   if (c == '\'' || c == '"') {
     char *s= filename + 1;
     char *t= filename;
     while (*s) {
       if (*s == c) {
           if (s[-1] == '\\')
               t[-1]= c;
       }else
           *t++= *s;
       s++;
     }
     *t= '\0';
   }
 } /* copyfilename */
 
 /*---------------------------------
 
   qh_countfacets( facetlist, facets, printall,
           numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
     count good facets for printing and set visitid
     if allfacets, ignores qh_skipfacet()
 
   notes:
     qh_printsummary and qh_countfacets must match counts
 
   returns:
     numfacets, numsimplicial, total neighbors, numridges, coplanars
     each facet with ->visitid indicating 1-relative position
       ->visitid==0 indicates not good
 
   notes
     numfacets >= numsimplicial
     if qh.NEWfacets,
       does not count visible facets (matches qh_printafacet)
 
   design:
     for all facets on facetlist and in facets set
       unless facet is skipped or visible (i.e., will be deleted)
         mark facet->visitid
         update counts
 */
 void qh_countfacets(facetT *facetlist, setT *facets, boolT printall,
     int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
   facetT *facet, **facetp;
   int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
 
   FORALLfacet_(facetlist) {
     if ((facet->visible && qh NEWfacets)
     || (!printall && qh_skipfacet(facet)))
       facet->visitid= 0;
     else {
       facet->visitid= ++numfacets;
       totneighbors += qh_setsize(facet->neighbors);
       if (facet->simplicial) {
         numsimplicial++;
         if (facet->keepcentrum && facet->tricoplanar)
           numtricoplanars++;
       }else
         numridges += qh_setsize(facet->ridges);
       if (facet->coplanarset)
         numcoplanars += qh_setsize(facet->coplanarset);
     }
   }
 
   FOREACHfacet_(facets) {
     if ((facet->visible && qh NEWfacets)
     || (!printall && qh_skipfacet(facet)))
       facet->visitid= 0;
     else {
       facet->visitid= ++numfacets;
       totneighbors += qh_setsize(facet->neighbors);
       if (facet->simplicial){
         numsimplicial++;
         if (facet->keepcentrum && facet->tricoplanar)
           numtricoplanars++;
       }else
         numridges += qh_setsize(facet->ridges);
       if (facet->coplanarset)
         numcoplanars += qh_setsize(facet->coplanarset);
     }
   }
   qh visit_id += numfacets+1;
   *numfacetsp= numfacets;
   *numsimplicialp= numsimplicial;
   *totneighborsp= totneighbors;
   *numridgesp= numridges;
   *numcoplanarsp= numcoplanars;
   *numtricoplanarsp= numtricoplanars;
 } /* countfacets */
 
 /*---------------------------------
 
   qh_detvnorm( vertex, vertexA, centers, offset )
     compute separating plane of the Voronoi diagram for a pair of input sites
     centers= set of facets (i.e., Voronoi vertices)
       facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
 
   assumes:
     qh_ASvoronoi and qh_vertexneighbors() already set
 
   returns:
     norm
       a pointer into qh.gm_matrix to qh.hull_dim-1 reals
       copy the data before reusing qh.gm_matrix
     offset
       if 'QVn'
         sign adjusted so that qh.GOODvertexp is inside
       else
         sign adjusted so that vertex is inside
 
     qh.gm_matrix= simplex of points from centers relative to first center
 
   notes:
     in io.c so that code for 'v Tv' can be removed by removing io.c
     returns pointer into qh.gm_matrix to avoid tracking of temporary memory
 
   design:
     determine midpoint of input sites
     build points as the set of Voronoi vertices
     select a simplex from points (if necessary)
       include midpoint if the Voronoi region is unbounded
     relocate the first vertex of the simplex to the origin
     compute the normalized hyperplane through the simplex
     orient the hyperplane toward 'QVn' or 'vertex'
     if 'Tv' or 'Ts'
       if bounded
         test that hyperplane is the perpendicular bisector of the input sites
       test that Voronoi vertices not in the simplex are still on the hyperplane
     free up temporary memory
 */
 pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
   facetT *facet, **facetp;
   int  i, k, pointid, pointidA, point_i, point_n;
   setT *simplex= NULL;
   pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
   coordT *coord, *gmcoord, *normalp;
   setT *points= qh_settemp(qh TEMPsize);
   boolT nearzero= False;
   boolT unbounded= False;
   int numcenters= 0;
   int dim= qh hull_dim - 1;
   realT dist, offset, angle, zero= 0.0;
 
   midpoint= qh gm_matrix + qh hull_dim * qh hull_dim;  /* last row */
   for (k=0; k < dim; k++)
     midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
   FOREACHfacet_(centers) {
     numcenters++;
     if (!facet->visitid)
       unbounded= True;
     else {
       if (!facet->center)
         facet->center= qh_facetcenter(facet->vertices);
       qh_setappend(&points, facet->center);
     }
   }
   if (numcenters > dim) {
     simplex= qh_settemp(qh TEMPsize);
     qh_setappend(&simplex, vertex->point);
     if (unbounded)
       qh_setappend(&simplex, midpoint);
     qh_maxsimplex(dim, points, NULL, 0, &simplex);
     qh_setdelnth(simplex, 0);
   }else if (numcenters == dim) {
     if (unbounded)
       qh_setappend(&points, midpoint);
     simplex= points;
   }else {
     qh_fprintf(qh ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   i= 0;
   gmcoord= qh gm_matrix;
   point0= SETfirstt_(simplex, pointT);
   FOREACHpoint_(simplex) {
     if (qh IStracing >= 4)
       qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint",
                               &point, 1, dim);
     if (point != point0) {
       qh gm_row[i++]= gmcoord;
       coord= point0;
       for (k=dim; k--; )
         *(gmcoord++)= *point++ - *coord++;
     }
   }
   qh gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
   normal= gmcoord;
   qh_sethyperplane_gauss(dim, qh gm_row, point0, True,
                 normal, &offset, &nearzero);
   if (qh GOODvertexp == vertexA->point)
     inpoint= vertexA->point;
   else
     inpoint= vertex->point;
   zinc_(Zdistio);
   dist= qh_distnorm(dim, inpoint, normal, &offset);
   if (dist > 0) {
     offset= -offset;
     normalp= normal;
     for (k=dim; k--; ) {
       *normalp= -(*normalp);
       normalp++;
     }
   }
   if (qh VERIFYoutput || qh PRINTstatistics) {
     pointid= qh_pointid(vertex->point);
     pointidA= qh_pointid(vertexA->point);
     if (!unbounded) {
       zinc_(Zdiststat);
       dist= qh_distnorm(dim, midpoint, normal, &offset);
       if (dist < 0)
         dist= -dist;
       zzinc_(Zridgemid);
       wwmax_(Wridgemidmax, dist);
       wwadd_(Wridgemid, dist);
       trace4((qh ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
                  pointid, pointidA, dist));
       for (k=0; k < dim; k++)
         midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
       qh_normalize(midpoint, dim, False);
       angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
       if (angle < 0.0)
         angle= angle + 1.0;
       else
         angle= angle - 1.0;
       if (angle < 0.0)
         angle -= angle;
       trace4((qh ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
                  pointid, pointidA, angle, nearzero));
       if (nearzero) {
         zzinc_(Zridge0);
         wwmax_(Wridge0max, angle);
         wwadd_(Wridge0, angle);
       }else {
         zzinc_(Zridgeok)
         wwmax_(Wridgeokmax, angle);
         wwadd_(Wridgeok, angle);
       }
     }
     if (simplex != points) {
       FOREACHpoint_i_(points) {
         if (!qh_setin(simplex, point)) {
           facet= SETelemt_(centers, point_i, facetT);
           zinc_(Zdiststat);
           dist= qh_distnorm(dim, point, normal, &offset);
           if (dist < 0)
             dist= -dist;
           zzinc_(Zridge);
           wwmax_(Wridgemax, dist);
           wwadd_(Wridge, dist);
           trace4((qh ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
                              pointid, pointidA, facet->visitid, dist));
         }
       }
     }
   }
   *offsetp= offset;
   if (simplex != points)
     qh_settempfree(&simplex);
   qh_settempfree(&points);
   return normal;
 } /* detvnorm */
 
 /*---------------------------------
 
   qh_detvridge( vertexA )
     determine Voronoi ridge from 'seen' neighbors of vertexA
     include one vertex-at-infinite if an !neighbor->visitid
 
   returns:
     temporary set of centers (facets, i.e., Voronoi vertices)
     sorted by center id
 */
 setT *qh_detvridge(vertexT *vertex) {
   setT *centers= qh_settemp(qh TEMPsize);
   setT *tricenters= qh_settemp(qh TEMPsize);
   facetT *neighbor, **neighborp;
   boolT firstinf= True;
 
   FOREACHneighbor_(vertex) {
     if (neighbor->seen) {
       if (neighbor->visitid) {
         if (!neighbor->tricoplanar || qh_setunique(&tricenters, neighbor->center))
           qh_setappend(¢ers, neighbor);
       }else if (firstinf) {
         firstinf= False;
         qh_setappend(¢ers, neighbor);
       }
     }
   }
   qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(centers),
              sizeof(facetT *), qh_compare_facetvisit);
   qh_settempfree(&tricenters);
   return centers;
 } /* detvridge */
 
 /*---------------------------------
 
   qh_detvridge3( atvertex, vertex )
     determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
     include one vertex-at-infinite for !neighbor->visitid
     assumes all facet->seen2= True
 
   returns:
     temporary set of centers (facets, i.e., Voronoi vertices)
     listed in adjacency order (!oriented)
     all facet->seen2= True
 
   design:
     mark all neighbors of atvertex
     for each adjacent neighbor of both atvertex and vertex
       if neighbor selected
         add neighbor to set of Voronoi vertices
 */
 setT *qh_detvridge3(vertexT *atvertex, vertexT *vertex) {
   setT *centers= qh_settemp(qh TEMPsize);
   setT *tricenters= qh_settemp(qh TEMPsize);
   facetT *neighbor, **neighborp, *facet= NULL;
   boolT firstinf= True;
 
   FOREACHneighbor_(atvertex)
     neighbor->seen2= False;
   FOREACHneighbor_(vertex) {
     if (!neighbor->seen2) {
       facet= neighbor;
       break;
     }
   }
   while (facet) {
     facet->seen2= True;
     if (neighbor->seen) {
       if (facet->visitid) {
         if (!facet->tricoplanar || qh_setunique(&tricenters, facet->center))
           qh_setappend(¢ers, facet);
       }else if (firstinf) {
         firstinf= False;
         qh_setappend(¢ers, facet);
       }
     }
     FOREACHneighbor_(facet) {
       if (!neighbor->seen2) {
         if (qh_setin(vertex->neighbors, neighbor))
           break;
         else
           neighbor->seen2= True;
       }
     }
     facet= neighbor;
   }
   if (qh CHECKfrequently) {
     FOREACHneighbor_(vertex) {
       if (!neighbor->seen2) {
           qh_fprintf(qh ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",
                  qh_pointid(vertex->point), neighbor->id);
         qh_errexit(qh_ERRqhull, neighbor, NULL);
       }
     }
   }
   FOREACHneighbor_(atvertex)
     neighbor->seen2= True;
   qh_settempfree(&tricenters);
   return centers;
 } /* detvridge3 */
 
 /*---------------------------------
 
   qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
     if visitall,
       visit all Voronoi ridges for vertex (i.e., an input site)
     else
       visit all unvisited Voronoi ridges for vertex
       all vertex->seen= False if unvisited
     assumes
       all facet->seen= False
       all facet->seen2= True (for qh_detvridge3)
       all facet->visitid == 0 if vertex_at_infinity
                          == index of Voronoi vertex
                          >= qh.num_facets if ignored
     innerouter:
       qh_RIDGEall--  both inner (bounded) and outer(unbounded) ridges
       qh_RIDGEinner- only inner
       qh_RIDGEouter- only outer
 
     if inorder
       orders vertices for 3-d Voronoi diagrams
 
   returns:
     number of visited ridges (does not include previously visited ridges)
 
     if printvridge,
       calls printvridge( fp, vertex, vertexA, centers)
         fp== any pointer (assumes FILE*)
         vertex,vertexA= pair of input sites that define a Voronoi ridge
         centers= set of facets (i.e., Voronoi vertices)
                  ->visitid == index or 0 if vertex_at_infinity
                  ordered for 3-d Voronoi diagram
   notes:
     uses qh.vertex_visit
 
   see:
     qh_eachvoronoi_all()
 
   design:
     mark selected neighbors of atvertex
     for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
       for each unvisited vertex
         if atvertex and vertex share more than d-1 neighbors
           bump totalcount
           if printvridge defined
             build the set of shared neighbors (i.e., Voronoi vertices)
             call printvridge
 */
 int qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
   boolT unbounded;
   int count;
   facetT *neighbor, **neighborp, *neighborA, **neighborAp;
   setT *centers;
   setT *tricenters= qh_settemp(qh TEMPsize);
 
   vertexT *vertex, **vertexp;
   boolT firstinf;
   unsigned int numfacets= (unsigned int)qh num_facets;
   int totridges= 0;
 
   qh vertex_visit++;
   atvertex->seen= True;
   if (visitall) {
     FORALLvertices
       vertex->seen= False;
   }
   FOREACHneighbor_(atvertex) {
     if (neighbor->visitid < numfacets)
       neighbor->seen= True;
   }
   FOREACHneighbor_(atvertex) {
     if (neighbor->seen) {
       FOREACHvertex_(neighbor->vertices) {
         if (vertex->visitid != qh vertex_visit && !vertex->seen) {
           vertex->visitid= qh vertex_visit;
           count= 0;
           firstinf= True;
           qh_settruncate(tricenters, 0);
           FOREACHneighborA_(vertex) {
             if (neighborA->seen) {
               if (neighborA->visitid) {
                 if (!neighborA->tricoplanar || qh_setunique(&tricenters, neighborA->center))
                   count++;
               }else if (firstinf) {
                 count++;
                 firstinf= False;
               }
             }
           }
           if (count >= qh hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
             if (firstinf) {
               if (innerouter == qh_RIDGEouter)
                 continue;
               unbounded= False;
             }else {
               if (innerouter == qh_RIDGEinner)
                 continue;
               unbounded= True;
             }
             totridges++;
             trace4((qh ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
                   count, qh_pointid(atvertex->point), qh_pointid(vertex->point)));
             if (printvridge && fp) {
               if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
                 centers= qh_detvridge3(atvertex, vertex);
               else
                 centers= qh_detvridge(vertex);
               (*printvridge)(fp, atvertex, vertex, centers, unbounded);
               qh_settempfree(¢ers);
             }
           }
         }
       }
     }
   }
   FOREACHneighbor_(atvertex)
     neighbor->seen= False;
   qh_settempfree(&tricenters);
   return totridges;
 } /* eachvoronoi */
 
 
 /*---------------------------------
 
   qh_eachvoronoi_all( fp, printvridge, isUpper, innerouter, inorder )
     visit all Voronoi ridges
 
     innerouter:
       see qh_eachvoronoi()
 
     if inorder
       orders vertices for 3-d Voronoi diagrams
 
   returns
     total number of ridges
 
     if isUpper == facet->upperdelaunay  (i.e., a Vornoi vertex)
       facet->visitid= Voronoi vertex index(same as 'o' format)
     else
       facet->visitid= 0
 
     if printvridge,
       calls printvridge( fp, vertex, vertexA, centers)
       [see qh_eachvoronoi]
 
   notes:
     Not used for qhull.exe
     same effect as qh_printvdiagram but ridges not sorted by point id
 */
 int qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {
   facetT *facet;
   vertexT *vertex;
   int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
   int totridges= 0;
 
   qh_clearcenters(qh_ASvoronoi);
   qh_vertexneighbors();
   maximize_(qh visit_id, (unsigned) qh num_facets);
   FORALLfacets {
     facet->visitid= 0;
     facet->seen= False;
     facet->seen2= True;
   }
   FORALLfacets {
     if (facet->upperdelaunay == isUpper)
       facet->visitid= numcenters++;
   }
   FORALLvertices
     vertex->seen= False;
   FORALLvertices {
     if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
       continue;
     totridges += qh_eachvoronoi(fp, printvridge, vertex,
                    !qh_ALL, innerouter, inorder);
   }
   return totridges;
 } /* eachvoronoi_all */
 
 /*---------------------------------
 
   qh_facet2point( facet, point0, point1, mindist )
     return two projected temporary vertices for a 2-d facet
     may be non-simplicial
 
   returns:
     point0 and point1 oriented and projected to the facet
     returns mindist (maximum distance below plane)
 */
 void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
   vertexT *vertex0, *vertex1;
   realT dist;
 
   if (facet->toporient ^ qh_ORIENTclock) {
     vertex0= SETfirstt_(facet->vertices, vertexT);
     vertex1= SETsecondt_(facet->vertices, vertexT);
   }else {
     vertex1= SETfirstt_(facet->vertices, vertexT);
     vertex0= SETsecondt_(facet->vertices, vertexT);
   }
   zadd_(Zdistio, 2);
   qh_distplane(vertex0->point, facet, &dist);
   *mindist= dist;
   *point0= qh_projectpoint(vertex0->point, facet, dist);
   qh_distplane(vertex1->point, facet, &dist);
   minimize_(*mindist, dist);
   *point1= qh_projectpoint(vertex1->point, facet, dist);
 } /* facet2point */
 
 
 /*---------------------------------
 
   qh_facetvertices( facetlist, facets, allfacets )
     returns temporary set of vertices in a set and/or list of facets
     if allfacets, ignores qh_skipfacet()
 
   returns:
     vertices with qh.vertex_visit
 
   notes:
     optimized for allfacets of facet_list
 
   design:
     if allfacets of facet_list
       create vertex set from vertex_list
     else
       for each selected facet in facets or facetlist
         append unvisited vertices to vertex set
 */
 setT *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets) {
   setT *vertices;
   facetT *facet, **facetp;
   vertexT *vertex, **vertexp;
 
   qh vertex_visit++;
   if (facetlist == qh facet_list && allfacets && !facets) {
     vertices= qh_settemp(qh num_vertices);
     FORALLvertices {
       vertex->visitid= qh vertex_visit;
       qh_setappend(&vertices, vertex);
     }
   }else {
     vertices= qh_settemp(qh TEMPsize);
     FORALLfacet_(facetlist) {
       if (!allfacets && qh_skipfacet(facet))
         continue;
       FOREACHvertex_(facet->vertices) {
         if (vertex->visitid != qh vertex_visit) {
           vertex->visitid= qh vertex_visit;
           qh_setappend(&vertices, vertex);
         }
       }
     }
   }
   FOREACHfacet_(facets) {
     if (!allfacets && qh_skipfacet(facet))
       continue;
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh vertex_visit) {
         vertex->visitid= qh vertex_visit;
         qh_setappend(&vertices, vertex);
       }
     }
   }
   return vertices;
 } /* facetvertices */
 
 /*---------------------------------
 
   qh_geomplanes( facet, outerplane, innerplane )
     return outer and inner planes for Geomview
     qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
 
   notes:
     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
 */
 void qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane) {
   realT radius;
 
   if (qh MERGING || qh JOGGLEmax < REALmax/2) {
     qh_outerinner(facet, outerplane, innerplane);
     radius= qh PRINTradius;
     if (qh JOGGLEmax < REALmax/2)
       radius -= qh JOGGLEmax * sqrt((realT)qh hull_dim);  /* already accounted for in qh_outerinner() */
     *outerplane += radius;
     *innerplane -= radius;
     if (qh PRINTcoplanar || qh PRINTspheres) {
       *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
       *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
     }
   }else
     *innerplane= *outerplane= 0;
 } /* geomplanes */
 
 
 /*---------------------------------
 
   qh_markkeep( facetlist )
     mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
     ignores visible facets (!part of convex hull)
 
   returns:
     may clear facet->good
     recomputes qh.num_good
 
   design:
     get set of good facets
     if qh.KEEParea
       sort facets by area
       clear facet->good for all but n largest facets
     if qh.KEEPmerge
       sort facets by merge count
       clear facet->good for all but n most merged facets
     if qh.KEEPminarea
       clear facet->good if area too small
     update qh.num_good
 */
 void qh_markkeep(facetT *facetlist) {
   facetT *facet, **facetp;
   setT *facets= qh_settemp(qh num_facets);
   int size, count;
 
   trace2((qh ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
           qh KEEParea, qh KEEPmerge, qh KEEPminArea));
   FORALLfacet_(facetlist) {
     if (!facet->visible && facet->good)
       qh_setappend(&facets, facet);
   }
   size= qh_setsize(facets);
   if (qh KEEParea) {
     qsort(SETaddr_(facets, facetT), (size_t)size,
              sizeof(facetT *), qh_compare_facetarea);
     if ((count= size - qh KEEParea) > 0) {
       FOREACHfacet_(facets) {
         facet->good= False;
         if (--count == 0)
           break;
       }
     }
   }
   if (qh KEEPmerge) {
     qsort(SETaddr_(facets, facetT), (size_t)size,
              sizeof(facetT *), qh_compare_facetmerge);
     if ((count= size - qh KEEPmerge) > 0) {
       FOREACHfacet_(facets) {
         facet->good= False;
         if (--count == 0)
           break;
       }
     }
   }
   if (qh KEEPminArea < REALmax/2) {
     FOREACHfacet_(facets) {
       if (!facet->isarea || facet->f.area < qh KEEPminArea)
         facet->good= False;
     }
   }
   qh_settempfree(&facets);
   count= 0;
   FORALLfacet_(facetlist) {
     if (facet->good)
       count++;
   }
   qh num_good= count;
 } /* markkeep */
 
 
 /*---------------------------------
 
   qh_markvoronoi( facetlist, facets, printall, isLower, numcenters )
     mark voronoi vertices for printing by site pairs
 
   returns:
     temporary set of vertices indexed by pointid
     isLower set if printing lower hull (i.e., at least one facet is lower hull)
     numcenters= total number of Voronoi vertices
     bumps qh.printoutnum for vertex-at-infinity
     clears all facet->seen and sets facet->seen2
 
     if selected
       facet->visitid= Voronoi vertex id
     else if upper hull (or 'Qu' and lower hull)
       facet->visitid= 0
     else
       facet->visitid >= qh num_facets
 
   notes:
     ignores qh.ATinfinity, if defined
 */
 setT *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {
   int numcenters=0;
   facetT *facet, **facetp;
   setT *vertices;
   boolT isLower= False;
 
   qh printoutnum++;
   qh_clearcenters(qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
   qh_vertexneighbors();
   vertices= qh_pointvertex();
   if (qh ATinfinity)
     SETelem_(vertices, qh num_points-1)= NULL;
   qh visit_id++;
   maximize_(qh visit_id, (unsigned) qh num_facets);
   FORALLfacet_(facetlist) {
     if (printall || !qh_skipfacet(facet)) {
       if (!facet->upperdelaunay) {
         isLower= True;
         break;
       }
     }
   }
   FOREACHfacet_(facets) {
     if (printall || !qh_skipfacet(facet)) {
       if (!facet->upperdelaunay) {
         isLower= True;
         break;
       }
     }
   }
   FORALLfacets {
     if (facet->normal && (facet->upperdelaunay == isLower))
       facet->visitid= 0;  /* facetlist or facets may overwrite */
     else
       facet->visitid= qh visit_id;
     facet->seen= False;
     facet->seen2= True;
   }
   numcenters++;  /* qh_INFINITE */
   FORALLfacet_(facetlist) {
     if (printall || !qh_skipfacet(facet))
       facet->visitid= numcenters++;
   }
   FOREACHfacet_(facets) {
     if (printall || !qh_skipfacet(facet))
       facet->visitid= numcenters++;
   }
   *isLowerp= isLower;
   *numcentersp= numcenters;
   trace2((qh ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));
   return vertices;
 } /* markvoronoi */
 
 /*---------------------------------
 
   qh_order_vertexneighbors( vertex )
     order facet neighbors of a 2-d or 3-d vertex by adjacency
 
   notes:
     does not orient the neighbors
 
   design:
     initialize a new neighbor set with the first facet in vertex->neighbors
     while vertex->neighbors non-empty
       select next neighbor in the previous facet's neighbor set
     set vertex->neighbors to the new neighbor set
 */
 void qh_order_vertexneighbors(vertexT *vertex) {
   setT *newset;
   facetT *facet, *neighbor, **neighborp;
 
   trace4((qh ferr, 4018, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
   newset= qh_settemp(qh_setsize(vertex->neighbors));
   facet= (facetT*)qh_setdellast(vertex->neighbors);
   qh_setappend(&newset, facet);
   while (qh_setsize(vertex->neighbors)) {
     FOREACHneighbor_(vertex) {
       if (qh_setin(facet->neighbors, neighbor)) {
         qh_setdel(vertex->neighbors, neighbor);
         qh_setappend(&newset, neighbor);
         facet= neighbor;
         break;
       }
     }
     if (!neighbor) {
       qh_fprintf(qh ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
         vertex->id, facet->id);
       qh_errexit(qh_ERRqhull, facet, NULL);
     }
   }
   qh_setfree(&vertex->neighbors);
   qh_settemppop();
   vertex->neighbors= newset;
 } /* order_vertexneighbors */
 
 /*---------------------------------
 
   qh_prepare_output( )
     prepare for qh_produce_output2() according to
       qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds
     does not reset facet->good
 
   notes
     except for PRINTstatistics, no-op if previously called with same options
 */
 void qh_prepare_output(void) {
   if (qh VORONOI) {
     qh_clearcenters(qh_ASvoronoi);
     qh_vertexneighbors();
   }
   if (qh TRIangulate && !qh hasTriangulation) {
     qh_triangulate();
     if (qh VERIFYoutput && !qh CHECKfrequently)
       qh_checkpolygon(qh facet_list);
   }
   qh_findgood_all(qh facet_list);
   if (qh GETarea)
     qh_getarea(qh facet_list);
   if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
     qh_markkeep(qh facet_list);
   if (qh PRINTstatistics)
     qh_collectstatistics();
 }
 
 /*---------------------------------
 
   qh_printafacet( fp, format, facet, printall )
     print facet to fp in given output format (see qh.PRINTout)
 
   returns:
     nop if !printall and qh_skipfacet()
     nop if visible facet and NEWfacets and format != PRINTfacets
     must match qh_countfacets
 
   notes
     preserves qh.visit_id
     facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
 
   see
     qh_printbegin() and qh_printend()
 
   design:
     test for printing facet
     call appropriate routine for format
     or output results directly
 */
 void qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {
   realT color[4], offset, dist, outerplane, innerplane;
   boolT zerodiv;
   coordT *point, *normp, *coordp, **pointp, *feasiblep;
   int k;
   vertexT *vertex, **vertexp;
   facetT *neighbor, **neighborp;
 
   if (!printall && qh_skipfacet(facet))
     return;
   if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
     return;
   qh printoutnum++;
   switch (format) {
   case qh_PRINTarea:
     if (facet->isarea) {
       qh_fprintf(fp, 9009, qh_REAL_1, facet->f.area);
       qh_fprintf(fp, 9010, "\n");
     }else
       qh_fprintf(fp, 9011, "0\n");
     break;
   case qh_PRINTcoplanars:
     qh_fprintf(fp, 9012, "%d", qh_setsize(facet->coplanarset));
     FOREACHpoint_(facet->coplanarset)
       qh_fprintf(fp, 9013, " %d", qh_pointid(point));
     qh_fprintf(fp, 9014, "\n");
     break;
   case qh_PRINTcentrums:
     qh_printcenter(fp, format, NULL, facet);
     break;
   case qh_PRINTfacets:
     qh_printfacet(fp, facet);
     break;
   case qh_PRINTfacets_xridge:
     qh_printfacetheader(fp, facet);
     break;
   case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
     if (!facet->normal)
       break;
     for (k=qh hull_dim; k--; ) {
       color[k]= (facet->normal[k]+1.0)/2.0;
       maximize_(color[k], -1.0);
       minimize_(color[k], +1.0);
     }
     qh_projectdim3(color, color);
     if (qh PRINTdim != qh hull_dim)
       qh_normalize2(color, 3, True, NULL, NULL);
     if (qh hull_dim <= 2)
       qh_printfacet2geom(fp, facet, color);
     else if (qh hull_dim == 3) {
       if (facet->simplicial)
         qh_printfacet3geom_simplicial(fp, facet, color);
       else
         qh_printfacet3geom_nonsimplicial(fp, facet, color);
     }else {
       if (facet->simplicial)
         qh_printfacet4geom_simplicial(fp, facet, color);
       else
         qh_printfacet4geom_nonsimplicial(fp, facet, color);
     }
     break;
   case qh_PRINTids:
     qh_fprintf(fp, 9015, "%d\n", facet->id);
     break;
   case qh_PRINTincidences:
   case qh_PRINToff:
   case qh_PRINTtriangles:
     if (qh hull_dim == 3 && format != qh_PRINTtriangles)
       qh_printfacet3vertex(fp, facet, format);
     else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
       qh_printfacetNvertex_simplicial(fp, facet, format);
     else
       qh_printfacetNvertex_nonsimplicial(fp, facet, qh printoutvar++, format);
     break;
   case qh_PRINTinner:
     qh_outerinner(facet, NULL, &innerplane);
     offset= facet->offset - innerplane;
     goto LABELprintnorm;
     break; /* prevent warning */
   case qh_PRINTmerges:
     qh_fprintf(fp, 9016, "%d\n", facet->nummerge);
     break;
   case qh_PRINTnormals:
     offset= facet->offset;
     goto LABELprintnorm;
     break; /* prevent warning */
   case qh_PRINTouter:
     qh_outerinner(facet, &outerplane, NULL);
     offset= facet->offset - outerplane;
   LABELprintnorm:
     if (!facet->normal) {
       qh_fprintf(fp, 9017, "no normal for facet f%d\n", facet->id);
       break;
     }
     if (qh CDDoutput) {
       qh_fprintf(fp, 9018, qh_REAL_1, -offset);
       for (k=0; k < qh hull_dim; k++)
         qh_fprintf(fp, 9019, qh_REAL_1, -facet->normal[k]);
     }else {
       for (k=0; k < qh hull_dim; k++)
         qh_fprintf(fp, 9020, qh_REAL_1, facet->normal[k]);
       qh_fprintf(fp, 9021, qh_REAL_1, offset);
     }
     qh_fprintf(fp, 9022, "\n");
     break;
   case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
   case qh_PRINTmaple:
     if (qh hull_dim == 2)
       qh_printfacet2math(fp, facet, format, qh printoutvar++);
     else
       qh_printfacet3math(fp, facet, format, qh printoutvar++);
     break;
   case qh_PRINTneighbors:
     qh_fprintf(fp, 9023, "%d", qh_setsize(facet->neighbors));
     FOREACHneighbor_(facet)
       qh_fprintf(fp, 9024, " %d",
                neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);
     qh_fprintf(fp, 9025, "\n");
     break;
   case qh_PRINTpointintersect:
     if (!qh feasible_point) {
       qh_fprintf(qh ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
       qh_errexit( qh_ERRinput, NULL, NULL);
     }
     if (facet->offset > 0)
       goto LABELprintinfinite;
     point= coordp= (coordT*)qh_memalloc(qh normal_size);
     normp= facet->normal;
     feasiblep= qh feasible_point;
     if (facet->offset < -qh MINdenom) {
       for (k=qh hull_dim; k--; )
         *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
     }else {
       for (k=qh hull_dim; k--; ) {
         *(coordp++)= qh_divzero(*(normp++), facet->offset, qh MINdenom_1,
                                  &zerodiv) + *(feasiblep++);
         if (zerodiv) {
           qh_memfree(point, qh normal_size);
           goto LABELprintinfinite;
         }
       }
     }
     qh_printpoint(fp, NULL, point);
     qh_memfree(point, qh normal_size);
     break;
   LABELprintinfinite:
     for (k=qh hull_dim; k--; )
       qh_fprintf(fp, 9026, qh_REAL_1, qh_INFINITE);
     qh_fprintf(fp, 9027, "\n");
     break;
   case qh_PRINTpointnearest:
     FOREACHpoint_(facet->coplanarset) {
       int id, id2;
       vertex= qh_nearvertex(facet, point, &dist);
       id= qh_pointid(vertex->point);
       id2= qh_pointid(point);
       qh_fprintf(fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
     }
     break;
   case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
     if (qh CDDoutput)
       qh_fprintf(fp, 9029, "1 ");
     qh_printcenter(fp, format, NULL, facet);
     break;
   case qh_PRINTvertices:
     qh_fprintf(fp, 9030, "%d", qh_setsize(facet->vertices));
     FOREACHvertex_(facet->vertices)
       qh_fprintf(fp, 9031, " %d", qh_pointid(vertex->point));
     qh_fprintf(fp, 9032, "\n");
     break;
   default:
     break;
   }
 } /* printafacet */
 
 /*---------------------------------
 
   qh_printbegin(  )
     prints header for all output formats
 
   returns:
     checks for valid format
 
   notes:
     uses qh.visit_id for 3/4off
     changes qh.interior_point if printing centrums
     qh_countfacets clears facet->visitid for non-good facets
 
   see
     qh_printend() and qh_printafacet()
 
   design:
     count facets and related statistics
     print header for format
 */
 void qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
   int i, num;
   facetT *facet, **facetp;
   vertexT *vertex, **vertexp;
   setT *vertices;
   pointT *point, **pointp, *pointtemp;
 
   qh printoutnum= 0;
   qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
   switch (format) {
   case qh_PRINTnone:
     break;
   case qh_PRINTarea:
     qh_fprintf(fp, 9033, "%d\n", numfacets);
     break;
   case qh_PRINTcoplanars:
     qh_fprintf(fp, 9034, "%d\n", numfacets);
     break;
   case qh_PRINTcentrums:
     if (qh CENTERtype == qh_ASnone)
       qh_clearcenters(qh_AScentrum);
     qh_fprintf(fp, 9035, "%d\n%d\n", qh hull_dim, numfacets);
     break;
   case qh_PRINTfacets:
   case qh_PRINTfacets_xridge:
     if (facetlist)
       qh_printvertexlist(fp, "Vertices and facets:\n", facetlist, facets, printall);
     break;
   case qh_PRINTgeom:
     if (qh hull_dim > 4)  /* qh_initqhull_globals also checks */
       goto LABELnoformat;
     if (qh VORONOI && qh hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
       goto LABELnoformat;
     if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
       qh_fprintf(qh ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
     if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
                              (qh PRINTdim == 4 && qh PRINTcentrums)))
       qh_fprintf(qh ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
     if (qh PRINTdim == 4 && (qh PRINTspheres))
       qh_fprintf(qh ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");
     if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
       qh_fprintf(qh ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");
     if (qh PRINTdim == 2) {
       qh_fprintf(fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",
               qh rbox_command, qh qhull_command);
     }else if (qh PRINTdim == 3) {
       qh_fprintf(fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
               qh rbox_command, qh qhull_command);
     }else if (qh PRINTdim == 4) {
       qh visit_id++;
       num= 0;
       FORALLfacet_(facetlist)    /* get number of ridges to be printed */
         qh_printend4geom(NULL, facet, &num, printall);
       FOREACHfacet_(facets)
         qh_printend4geom(NULL, facet, &num, printall);
       qh ridgeoutnum= num;
       qh printoutvar= 0;  /* counts number of ridges in output */
       qh_fprintf(fp, 9038, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
     }
 
     if (qh PRINTdots) {
       qh printoutnum++;
       num= qh num_points + qh_setsize(qh other_points);
       if (qh DELAUNAY && qh ATinfinity)
         num--;
       if (qh PRINTdim == 4)
         qh_fprintf(fp, 9039, "4VECT %d %d 1\n", num, num);
       else
         qh_fprintf(fp, 9040, "VECT %d %d 1\n", num, num);
 
       for (i=num; i--; ) {
         if (i % 20 == 0)
           qh_fprintf(fp, 9041, "\n");
         qh_fprintf(fp, 9042, "1 ");
       }
       qh_fprintf(fp, 9043, "# 1 point per line\n1 ");
       for (i=num-1; i--; ) { /* num at least 3 for D2 */
         if (i % 20 == 0)
           qh_fprintf(fp, 9044, "\n");
         qh_fprintf(fp, 9045, "0 ");
       }
       qh_fprintf(fp, 9046, "# 1 color for all\n");
       FORALLpoints {
         if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
           if (qh PRINTdim == 4)
             qh_printpoint(fp, NULL, point);
             else
               qh_printpoint3(fp, point);
         }
       }
       FOREACHpoint_(qh other_points) {
         if (qh PRINTdim == 4)
           qh_printpoint(fp, NULL, point);
         else
           qh_printpoint3(fp, point);
       }
       qh_fprintf(fp, 9047, "0 1 1 1  # color of points\n");
     }
 
     if (qh PRINTdim == 4  && !qh PRINTnoplanes)
       /* 4dview loads up multiple 4OFF objects slowly */
       qh_fprintf(fp, 9048, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
     qh PRINTcradius= 2 * qh DISTround;  /* include test DISTround */
     if (qh PREmerge) {
       maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
     }else if (qh POSTmerge)
       maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
     qh PRINTradius= qh PRINTcradius;
     if (qh PRINTspheres + qh PRINTcoplanar)
       maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
     if (qh premerge_cos < REALmax/2) {
       maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
     }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
       maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
     }
     maximize_(qh PRINTradius, qh MINvisible);
     if (qh JOGGLEmax < REALmax/2)
       qh PRINTradius += qh JOGGLEmax * sqrt((realT)qh hull_dim);
     if (qh PRINTdim != 4 &&
         (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
       vertices= qh_facetvertices(facetlist, facets, printall);
       if (qh PRINTspheres && qh PRINTdim <= 3)
         qh_printspheres(fp, vertices, qh PRINTradius);
       if (qh PRINTcoplanar || qh PRINTcentrums) {
         qh firstcentrum= True;
         if (qh PRINTcoplanar&& !qh PRINTspheres) {
           FOREACHvertex_(vertices)
             qh_printpointvect2(fp, vertex->point, NULL, qh interior_point, qh PRINTradius);
         }
         FORALLfacet_(facetlist) {
           if (!printall && qh_skipfacet(facet))
             continue;
           if (!facet->normal)
             continue;
           if (qh PRINTcentrums && qh PRINTdim <= 3)
             qh_printcentrum(fp, facet, qh PRINTcradius);
           if (!qh PRINTcoplanar)
             continue;
           FOREACHpoint_(facet->coplanarset)
             qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
           FOREACHpoint_(facet->outsideset)
             qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
         }
         FOREACHfacet_(facets) {
           if (!printall && qh_skipfacet(facet))
             continue;
           if (!facet->normal)
             continue;
           if (qh PRINTcentrums && qh PRINTdim <= 3)
             qh_printcentrum(fp, facet, qh PRINTcradius);
           if (!qh PRINTcoplanar)
             continue;
           FOREACHpoint_(facet->coplanarset)
             qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
           FOREACHpoint_(facet->outsideset)
             qh_printpointvect2(fp, point, facet->normal, NULL, qh PRINTradius);
         }
       }
       qh_settempfree(&vertices);
     }
     qh visit_id++; /* for printing hyperplane intersections */
     break;
   case qh_PRINTids:
     qh_fprintf(fp, 9049, "%d\n", numfacets);
     break;
   case qh_PRINTincidences:
     if (qh VORONOI && qh PRINTprecision)
       qh_fprintf(qh ferr, 7053, "qhull warning: writing Delaunay.  Use 'p' or 'o' for Voronoi centers\n");
     qh printoutvar= qh vertex_id;  /* centrum id for non-simplicial facets */
     if (qh hull_dim <= 3)
       qh_fprintf(fp, 9050, "%d\n", numfacets);
     else
       qh_fprintf(fp, 9051, "%d\n", numsimplicial+numridges);
     break;
   case qh_PRINTinner:
   case qh_PRINTnormals:
   case qh_PRINTouter:
     if (qh CDDoutput)
       qh_fprintf(fp, 9052, "%s | %s\nbegin\n    %d %d real\n", qh rbox_command,
             qh qhull_command, numfacets, qh hull_dim+1);
     else
       qh_fprintf(fp, 9053, "%d\n%d\n", qh hull_dim+1, numfacets);
     break;
   case qh_PRINTmathematica:
   case qh_PRINTmaple:
     if (qh hull_dim > 3)  /* qh_initbuffers also checks */
       goto LABELnoformat;
     if (qh VORONOI)
       qh_fprintf(qh ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");
     if (format == qh_PRINTmaple) {
       if (qh hull_dim == 2)
         qh_fprintf(fp, 9054, "PLOT(CURVES(\n");
       else
         qh_fprintf(fp, 9055, "PLOT3D(POLYGONS(\n");
     }else
       qh_fprintf(fp, 9056, "{\n");
     qh printoutvar= 0;   /* counts number of facets for notfirst */
     break;
   case qh_PRINTmerges:
     qh_fprintf(fp, 9057, "%d\n", numfacets);
     break;
   case qh_PRINTpointintersect:
     qh_fprintf(fp, 9058, "%d\n%d\n", qh hull_dim, numfacets);
     break;
   case qh_PRINTneighbors:
     qh_fprintf(fp, 9059, "%d\n", numfacets);
     break;
   case qh_PRINToff:
   case qh_PRINTtriangles:
     if (qh VORONOI)
       goto LABELnoformat;
     num = qh hull_dim;
     if (format == qh_PRINToff || qh hull_dim == 2)
       qh_fprintf(fp, 9060, "%d\n%d %d %d\n", num,
         qh num_points+qh_setsize(qh other_points), numfacets, totneighbors/2);
     else { /* qh_PRINTtriangles */
       qh printoutvar= qh num_points+qh_setsize(qh other_points); /* first centrum */
       if (qh DELAUNAY)
         num--;  /* drop last dimension */
       qh_fprintf(fp, 9061, "%d\n%d %d %d\n", num, qh printoutvar
         + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
     }
     FORALLpoints
       qh_printpointid(qh fout, NULL, num, point, -1);
     FOREACHpoint_(qh other_points)
       qh_printpointid(qh fout, NULL, num, point, -1);
     if (format == qh_PRINTtriangles && qh hull_dim > 2) {
       FORALLfacets {
         if (!facet->simplicial && facet->visitid)
           qh_printcenter(qh fout, format, NULL, facet);
       }
     }
     break;
   case qh_PRINTpointnearest:
     qh_fprintf(fp, 9062, "%d\n", numcoplanars);
     break;
   case qh_PRINTpoints:
     if (!qh VORONOI)
       goto LABELnoformat;
     if (qh CDDoutput)
       qh_fprintf(fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
            qh qhull_command, numfacets, qh hull_dim);
     else
       qh_fprintf(fp, 9064, "%d\n%d\n", qh hull_dim-1, numfacets);
     break;
   case qh_PRINTvertices:
     qh_fprintf(fp, 9065, "%d\n", numfacets);
     break;
   case qh_PRINTsummary:
   default:
   LABELnoformat:
     qh_fprintf(qh ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
          qh hull_dim);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
 } /* printbegin */
 
 /*---------------------------------
 
   qh_printcenter( fp, string, facet )
     print facet->center as centrum or Voronoi center
     string may be NULL.  Don't include '%' codes.
     nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
     if upper envelope of Delaunay triangulation and point at-infinity
       prints qh_INFINITE instead;
 
   notes:
     defines facet->center if needed
     if format=PRINTgeom, adds a 0 if would otherwise be 2-d
     Same as QhullFacet::printCenter
 */
 void qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet) {
   int k, num;
 
   if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
     return;
   if (string)
     qh_fprintf(fp, 9066, string);
   if (qh CENTERtype == qh_ASvoronoi) {
     num= qh hull_dim-1;
     if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
       if (!facet->center)
         facet->center= qh_facetcenter(facet->vertices);
       for (k=0; k < num; k++)
         qh_fprintf(fp, 9067, qh_REAL_1, facet->center[k]);
     }else {
       for (k=0; k < num; k++)
         qh_fprintf(fp, 9068, qh_REAL_1, qh_INFINITE);
     }
   }else /* qh.CENTERtype == qh_AScentrum */ {
     num= qh hull_dim;
     if (format == qh_PRINTtriangles && qh DELAUNAY)
       num--;
     if (!facet->center)
       facet->center= qh_getcentrum(facet);
     for (k=0; k < num; k++)
       qh_fprintf(fp, 9069, qh_REAL_1, facet->center[k]);
   }
   if (format == qh_PRINTgeom && num == 2)
     qh_fprintf(fp, 9070, " 0\n");
   else
     qh_fprintf(fp, 9071, "\n");
 } /* printcenter */
 
 /*---------------------------------
 
   qh_printcentrum( fp, facet, radius )
     print centrum for a facet in OOGL format
     radius defines size of centrum
     2-d or 3-d only
 
   returns:
     defines facet->center if needed
 */
 void qh_printcentrum(FILE *fp, facetT *facet, realT radius) {
   pointT *centrum, *projpt;
   boolT tempcentrum= False;
   realT xaxis[4], yaxis[4], normal[4], dist;
   realT green[3]={0, 1, 0};
   vertexT *apex;
   int k;
 
   if (qh CENTERtype == qh_AScentrum) {
     if (!facet->center)
       facet->center= qh_getcentrum(facet);
     centrum= facet->center;
   }else {
     centrum= qh_getcentrum(facet);
     tempcentrum= True;
   }
   qh_fprintf(fp, 9072, "{appearance {-normal -edge normscale 0} ");
   if (qh firstcentrum) {
     qh firstcentrum= False;
     qh_fprintf(fp, 9073, "{INST geom { define centrum CQUAD  # f%d\n\
 -0.3 -0.3 0.0001     0 0 1 1\n\
  0.3 -0.3 0.0001     0 0 1 1\n\
  0.3  0.3 0.0001     0 0 1 1\n\
 -0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
   }else
     qh_fprintf(fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);
   apex= SETfirstt_(facet->vertices, vertexT);
   qh_distplane(apex->point, facet, &dist);
   projpt= qh_projectpoint(apex->point, facet, dist);
   for (k=qh hull_dim; k--; ) {
     xaxis[k]= projpt[k] - centrum[k];
     normal[k]= facet->normal[k];
   }
   if (qh hull_dim == 2) {
     xaxis[2]= 0;
     normal[2]= 0;
   }else if (qh hull_dim == 4) {
     qh_projectdim3(xaxis, xaxis);
     qh_projectdim3(normal, normal);
     qh_normalize2(normal, qh PRINTdim, True, NULL, NULL);
   }
   qh_crossproduct(3, xaxis, normal, yaxis);
   qh_fprintf(fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
   qh_fprintf(fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
   qh_fprintf(fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
   qh_printpoint3(fp, centrum);
   qh_fprintf(fp, 9078, "1 }}}\n");
   qh_memfree(projpt, qh normal_size);
   qh_printpointvect(fp, centrum, facet->normal, NULL, radius, green);
   if (tempcentrum)
     qh_memfree(centrum, qh normal_size);
 } /* printcentrum */
 
 /*---------------------------------
 
   qh_printend( fp, format )
     prints trailer for all output formats
 
   see:
     qh_printbegin() and qh_printafacet()
 
 */
 void qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int num;
   facetT *facet, **facetp;
 
   if (!qh printoutnum)
     qh_fprintf(qh ferr, 7055, "qhull warning: no facets printed\n");
   switch (format) {
   case qh_PRINTgeom:
     if (qh hull_dim == 4 && qh DROPdim < 0  && !qh PRINTnoplanes) {
       qh visit_id++;
       num= 0;
       FORALLfacet_(facetlist)
         qh_printend4geom(fp, facet,&num, printall);
       FOREACHfacet_(facets)
         qh_printend4geom(fp, facet, &num, printall);
       if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
         qh_fprintf(qh ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num);
         qh_errexit(qh_ERRqhull, NULL, NULL);
       }
     }else
       qh_fprintf(fp, 9079, "}\n");
     break;
   case qh_PRINTinner:
   case qh_PRINTnormals:
   case qh_PRINTouter:
     if (qh CDDoutput)
       qh_fprintf(fp, 9080, "end\n");
     break;
   case qh_PRINTmaple:
     qh_fprintf(fp, 9081, "));\n");
     break;
   case qh_PRINTmathematica:
     qh_fprintf(fp, 9082, "}\n");
     break;
   case qh_PRINTpoints:
     if (qh CDDoutput)
       qh_fprintf(fp, 9083, "end\n");
     break;
   default:
     break;
   }
 } /* printend */
 
 /*---------------------------------
 
   qh_printend4geom( fp, facet, numridges, printall )
     helper function for qh_printbegin/printend
 
   returns:
     number of printed ridges
 
   notes:
     just counts printed ridges if fp=NULL
     uses facet->visitid
     must agree with qh_printfacet4geom...
 
   design:
     computes color for facet from its normal
     prints each ridge of facet
 */
 void qh_printend4geom(FILE *fp, facetT *facet, int *nump, boolT printall) {
   realT color[3];
   int i, num= *nump;
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
 
   if (!printall && qh_skipfacet(facet))
     return;
   if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
     return;
   if (!facet->normal)
     return;
   if (fp) {
     for (i=0; i < 3; i++) {
       color[i]= (facet->normal[i]+1.0)/2.0;
       maximize_(color[i], -1.0);
       minimize_(color[i], +1.0);
     }
   }
   facet->visitid= qh visit_id;
   if (facet->simplicial) {
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh visit_id) {
         if (fp)
           qh_fprintf(fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
                  3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                  facet->id, neighbor->id);
         num++;
       }
     }
   }else {
     FOREACHridge_(facet->ridges) {
       neighbor= otherfacet_(ridge, facet);
       if (neighbor->visitid != qh visit_id) {
         if (fp)
           qh_fprintf(fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
                  3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                  ridge->id, facet->id, neighbor->id);
         num++;
       }
     }
   }
   *nump= num;
 } /* printend4geom */
 
 /*---------------------------------
 
   qh_printextremes( fp, facetlist, facets, printall )
     print extreme points for convex hulls or halfspace intersections
 
   notes:
     #points, followed by ids, one per line
 
     sorted by id
     same order as qh_printpoints_out if no coplanar/interior points
 */
 void qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   setT *vertices, *points;
   pointT *point;
   vertexT *vertex, **vertexp;
   int id;
   int numpoints=0, point_i, point_n;
   int allpoints= qh num_points + qh_setsize(qh other_points);
 
   points= qh_settemp(allpoints);
   qh_setzero(points, 0, allpoints);
   vertices= qh_facetvertices(facetlist, facets, printall);
   FOREACHvertex_(vertices) {
     id= qh_pointid(vertex->point);
     if (id >= 0) {
       SETelem_(points, id)= vertex->point;
       numpoints++;
     }
   }
   qh_settempfree(&vertices);
   qh_fprintf(fp, 9086, "%d\n", numpoints);
   FOREACHpoint_i_(points) {
     if (point)
       qh_fprintf(fp, 9087, "%d\n", point_i);
   }
   qh_settempfree(&points);
 } /* printextremes */
 
 /*---------------------------------
 
   qh_printextremes_2d( fp, facetlist, facets, printall )
     prints point ids for facets in qh_ORIENTclock order
 
   notes:
     #points, followed by ids, one per line
     if facetlist/facets are disjoint than the output includes skips
     errors if facets form a loop
     does not print coplanar points
 */
 void qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
   setT *vertices;
   facetT *facet, *startfacet, *nextfacet;
   vertexT *vertexA, *vertexB;
 
   qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
   vertices= qh_facetvertices(facetlist, facets, printall);
   qh_fprintf(fp, 9088, "%d\n", qh_setsize(vertices));
   qh_settempfree(&vertices);
   if (!numfacets)
     return;
   facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
   qh vertex_visit++;
   qh visit_id++;
   do {
     if (facet->toporient ^ qh_ORIENTclock) {
       vertexA= SETfirstt_(facet->vertices, vertexT);
       vertexB= SETsecondt_(facet->vertices, vertexT);
       nextfacet= SETfirstt_(facet->neighbors, facetT);
     }else {
       vertexA= SETsecondt_(facet->vertices, vertexT);
       vertexB= SETfirstt_(facet->vertices, vertexT);
       nextfacet= SETsecondt_(facet->neighbors, facetT);
     }
     if (facet->visitid == qh visit_id) {
       qh_fprintf(qh ferr, 6218, "Qhull internal error (qh_printextremes_2d): loop in facet list.  facet %d nextfacet %d\n",
                  facet->id, nextfacet->id);
       qh_errexit2(qh_ERRqhull, facet, nextfacet);
     }
     if (facet->visitid) {
       if (vertexA->visitid != qh vertex_visit) {
         vertexA->visitid= qh vertex_visit;
         qh_fprintf(fp, 9089, "%d\n", qh_pointid(vertexA->point));
       }
       if (vertexB->visitid != qh vertex_visit) {
         vertexB->visitid= qh vertex_visit;
         qh_fprintf(fp, 9090, "%d\n", qh_pointid(vertexB->point));
       }
     }
     facet->visitid= qh visit_id;
     facet= nextfacet;
   }while (facet && facet != startfacet);
 } /* printextremes_2d */
 
 /*---------------------------------
 
   qh_printextremes_d( fp, facetlist, facets, printall )
     print extreme points of input sites for Delaunay triangulations
 
   notes:
     #points, followed by ids, one per line
 
     unordered
 */
 void qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   setT *vertices;
   vertexT *vertex, **vertexp;
   boolT upperseen, lowerseen;
   facetT *neighbor, **neighborp;
   int numpoints=0;
 
   vertices= qh_facetvertices(facetlist, facets, printall);
   qh_vertexneighbors();
   FOREACHvertex_(vertices) {
     upperseen= lowerseen= False;
     FOREACHneighbor_(vertex) {
       if (neighbor->upperdelaunay)
         upperseen= True;
       else
         lowerseen= True;
     }
     if (upperseen && lowerseen) {
       vertex->seen= True;
       numpoints++;
     }else
       vertex->seen= False;
   }
   qh_fprintf(fp, 9091, "%d\n", numpoints);
   FOREACHvertex_(vertices) {
     if (vertex->seen)
       qh_fprintf(fp, 9092, "%d\n", qh_pointid(vertex->point));
   }
   qh_settempfree(&vertices);
 } /* printextremes_d */
 
 /*---------------------------------
 
   qh_printfacet( fp, facet )
     prints all fields of a facet to fp
 
   notes:
     ridges printed in neighbor order
 */
 void qh_printfacet(FILE *fp, facetT *facet) {
 
   qh_printfacetheader(fp, facet);
   if (facet->ridges)
     qh_printfacetridges(fp, facet);
 } /* printfacet */
 
 
 /*---------------------------------
 
   qh_printfacet2geom( fp, facet, color )
     print facet as part of a 2-d VECT for Geomview
 
     notes:
       assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
       mindist is calculated within io.c.  maxoutside is calculated elsewhere
       so a DISTround error may have occured.
 */
 void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
   pointT *point0, *point1;
   realT mindist, innerplane, outerplane;
   int k;
 
   qh_facet2point(facet, &point0, &point1, &mindist);
   qh_geomplanes(facet, &outerplane, &innerplane);
   if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
     qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
   if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
                 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
     for (k=3; k--; )
       color[k]= 1.0 - color[k];
     qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
   }
   qh_memfree(point1, qh normal_size);
   qh_memfree(point0, qh normal_size);
 } /* printfacet2geom */
 
 /*---------------------------------
 
   qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
     prints a 2-d facet as a VECT with 2 points at some offset.
     The points are on the facet's plane.
 */
 void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
                                facetT *facet, realT offset, realT color[3]) {
   pointT *p1= point1, *p2= point2;
 
   qh_fprintf(fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);
   if (offset != 0.0) {
     p1= qh_projectpoint(p1, facet, -offset);
     p2= qh_projectpoint(p2, facet, -offset);
   }
   qh_fprintf(fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
            p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
   if (offset != 0.0) {
     qh_memfree(p1, qh normal_size);
     qh_memfree(p2, qh normal_size);
   }
   qh_fprintf(fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
 } /* printfacet2geom_points */
 
 
 /*---------------------------------
 
   qh_printfacet2math( fp, facet, format, notfirst )
     print 2-d Maple or Mathematica output for a facet
     may be non-simplicial
 
   notes:
     use %16.8f since Mathematica 2.2 does not handle exponential format
     see qh_printfacet3math
 */
 void qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
   pointT *point0, *point1;
   realT mindist;
   const char *pointfmt;
 
   qh_facet2point(facet, &point0, &point1, &mindist);
   if (notfirst)
     qh_fprintf(fp, 9096, ",");
   if (format == qh_PRINTmaple)
     pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
   else
     pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
   qh_fprintf(fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);
   qh_memfree(point1, qh normal_size);
   qh_memfree(point0, qh normal_size);
 } /* printfacet2math */
 
 
 /*---------------------------------
 
   qh_printfacet3geom_nonsimplicial( fp, facet, color )
     print Geomview OFF for a 3-d nonsimplicial facet.
     if DOintersections, prints ridges to unvisited neighbors(qh visit_id)
 
   notes
     uses facet->visitid for intersections and ridges
 */
 void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
   ridgeT *ridge, **ridgep;
   setT *projectedpoints, *vertices;
   vertexT *vertex, **vertexp, *vertexA, *vertexB;
   pointT *projpt, *point, **pointp;
   facetT *neighbor;
   realT dist, outerplane, innerplane;
   int cntvertices, k;
   realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
 
   qh_geomplanes(facet, &outerplane, &innerplane);
   vertices= qh_facet3vertex(facet); /* oriented */
   cntvertices= qh_setsize(vertices);
   projectedpoints= qh_settemp(cntvertices);
   FOREACHvertex_(vertices) {
     zinc_(Zdistio);
     qh_distplane(vertex->point, facet, &dist);
     projpt= qh_projectpoint(vertex->point, facet, dist);
     qh_setappend(&projectedpoints, projpt);
   }
   if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
     qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
   if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
                 outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
     for (k=3; k--; )
       color[k]= 1.0 - color[k];
     qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
   }
   FOREACHpoint_(projectedpoints)
     qh_memfree(point, qh normal_size);
   qh_settempfree(&projectedpoints);
   qh_settempfree(&vertices);
   if ((qh DOintersections || qh PRINTridges)
   && (!facet->visible || !qh NEWfacets)) {
     facet->visitid= qh visit_id;
     FOREACHridge_(facet->ridges) {
       neighbor= otherfacet_(ridge, facet);
       if (neighbor->visitid != qh visit_id) {
         if (qh DOintersections)
           qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
         if (qh PRINTridges) {
           vertexA= SETfirstt_(ridge->vertices, vertexT);
           vertexB= SETsecondt_(ridge->vertices, vertexT);
           qh_printline3geom(fp, vertexA->point, vertexB->point, green);
         }
       }
     }
   }
 } /* printfacet3geom_nonsimplicial */
 
 /*---------------------------------
 
   qh_printfacet3geom_points( fp, points, facet, offset )
     prints a 3-d facet as OFF Geomview object.
     offset is relative to the facet's hyperplane
     Facet is determined as a list of points
 */
 void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
   int k, n= qh_setsize(points), i;
   pointT *point, **pointp;
   setT *printpoints;
 
   qh_fprintf(fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);
   if (offset != 0.0) {
     printpoints= qh_settemp(n);
     FOREACHpoint_(points)
       qh_setappend(&printpoints, qh_projectpoint(point, facet, -offset));
   }else
     printpoints= points;
   FOREACHpoint_(printpoints) {
     for (k=0; k < qh hull_dim; k++) {
       if (k == qh DROPdim)
         qh_fprintf(fp, 9099, "0 ");
       else
         qh_fprintf(fp, 9100, "%8.4g ", point[k]);
     }
     if (printpoints != points)
       qh_memfree(point, qh normal_size);
     qh_fprintf(fp, 9101, "\n");
   }
   if (printpoints != points)
     qh_settempfree(&printpoints);
   qh_fprintf(fp, 9102, "%d ", n);
   for (i=0; i < n; i++)
     qh_fprintf(fp, 9103, "%d ", i);
   qh_fprintf(fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
 } /* printfacet3geom_points */
 
 
 /*---------------------------------
 
   qh_printfacet3geom_simplicial(  )
     print Geomview OFF for a 3-d simplicial facet.
 
   notes:
     may flip color
     uses facet->visitid for intersections and ridges
 
     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
     innerplane may be off by qh DISTround.  Maxoutside is calculated elsewhere
     so a DISTround error may have occured.
 */
 void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
   setT *points, *vertices;
   vertexT *vertex, **vertexp, *vertexA, *vertexB;
   facetT *neighbor, **neighborp;
   realT outerplane, innerplane;
   realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
   int k;
 
   qh_geomplanes(facet, &outerplane, &innerplane);
   vertices= qh_facet3vertex(facet);
   points= qh_settemp(qh TEMPsize);
   FOREACHvertex_(vertices)
     qh_setappend(&points, vertex->point);
   if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
     qh_printfacet3geom_points(fp, points, facet, outerplane, color);
   if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
               outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
     for (k=3; k--; )
       color[k]= 1.0 - color[k];
     qh_printfacet3geom_points(fp, points, facet, innerplane, color);
   }
   qh_settempfree(&points);
   qh_settempfree(&vertices);
   if ((qh DOintersections || qh PRINTridges)
   && (!facet->visible || !qh NEWfacets)) {
     facet->visitid= qh visit_id;
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh visit_id) {
         vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim,
                           SETindex_(facet->neighbors, neighbor), 0);
         if (qh DOintersections)
            qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black);
         if (qh PRINTridges) {
           vertexA= SETfirstt_(vertices, vertexT);
           vertexB= SETsecondt_(vertices, vertexT);
           qh_printline3geom(fp, vertexA->point, vertexB->point, green);
         }
         qh_setfree(&vertices);
       }
     }
   }
 } /* printfacet3geom_simplicial */
 
 /*---------------------------------
 
   qh_printfacet3math( fp, facet, notfirst )
     print 3-d Maple or Mathematica output for a facet
 
   notes:
     may be non-simplicial
     use %16.8f since Mathematica 2.2 does not handle exponential format
     see qh_printfacet2math
 */
 void qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
   vertexT *vertex, **vertexp;
   setT *points, *vertices;
   pointT *point, **pointp;
   boolT firstpoint= True;
   realT dist;
   const char *pointfmt, *endfmt;
 
   if (notfirst)
     qh_fprintf(fp, 9105, ",\n");
   vertices= qh_facet3vertex(facet);
   points= qh_settemp(qh_setsize(vertices));
   FOREACHvertex_(vertices) {
     zinc_(Zdistio);
     qh_distplane(vertex->point, facet, &dist);
     point= qh_projectpoint(vertex->point, facet, dist);
     qh_setappend(&points, point);
   }
   if (format == qh_PRINTmaple) {
     qh_fprintf(fp, 9106, "[");
     pointfmt= "[%16.8f, %16.8f, %16.8f]";
     endfmt= "]";
   }else {
     qh_fprintf(fp, 9107, "Polygon[{");
     pointfmt= "{%16.8f, %16.8f, %16.8f}";
     endfmt= "}]";
   }
   FOREACHpoint_(points) {
     if (firstpoint)
       firstpoint= False;
     else
       qh_fprintf(fp, 9108, ",\n");
     qh_fprintf(fp, 9109, pointfmt, point[0], point[1], point[2]);
   }
   FOREACHpoint_(points)
     qh_memfree(point, qh normal_size);
   qh_settempfree(&points);
   qh_settempfree(&vertices);
   qh_fprintf(fp, 9110, endfmt);
 } /* printfacet3math */
 
 
 /*---------------------------------
 
   qh_printfacet3vertex( fp, facet, format )
     print vertices in a 3-d facet as point ids
 
   notes:
     prints number of vertices first if format == qh_PRINToff
     the facet may be non-simplicial
 */
 void qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format) {
   vertexT *vertex, **vertexp;
   setT *vertices;
 
   vertices= qh_facet3vertex(facet);
   if (format == qh_PRINToff)
     qh_fprintf(fp, 9111, "%d ", qh_setsize(vertices));
   FOREACHvertex_(vertices)
     qh_fprintf(fp, 9112, "%d ", qh_pointid(vertex->point));
   qh_fprintf(fp, 9113, "\n");
   qh_settempfree(&vertices);
 } /* printfacet3vertex */
 
 
 /*---------------------------------
 
   qh_printfacet4geom_nonsimplicial(  )
     print Geomview 4OFF file for a 4d nonsimplicial facet
     prints all ridges to unvisited neighbors (qh.visit_id)
     if qh.DROPdim
       prints in OFF format
 
   notes:
     must agree with printend4geom()
 */
 void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
   facetT *neighbor;
   ridgeT *ridge, **ridgep;
   vertexT *vertex, **vertexp;
   pointT *point;
   int k;
   realT dist;
 
   facet->visitid= qh visit_id;
   if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
     return;
   FOREACHridge_(facet->ridges) {
     neighbor= otherfacet_(ridge, facet);
     if (neighbor->visitid == qh visit_id)
       continue;
     if (qh PRINTtransparent && !neighbor->good)
       continue;
     if (qh DOintersections)
       qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
     else {
       if (qh DROPdim >= 0)
         qh_fprintf(fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);
       else {
         qh printoutvar++;
         qh_fprintf(fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
       }
       FOREACHvertex_(ridge->vertices) {
         zinc_(Zdistio);
         qh_distplane(vertex->point,facet, &dist);
         point=qh_projectpoint(vertex->point,facet, dist);
         for (k=0; k < qh hull_dim; k++) {
           if (k != qh DROPdim)
             qh_fprintf(fp, 9116, "%8.4g ", point[k]);
         }
         qh_fprintf(fp, 9117, "\n");
         qh_memfree(point, qh normal_size);
       }
       if (qh DROPdim >= 0)
         qh_fprintf(fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
     }
   }
 } /* printfacet4geom_nonsimplicial */
 
 
 /*---------------------------------
 
   qh_printfacet4geom_simplicial( fp, facet, color )
     print Geomview 4OFF file for a 4d simplicial facet
     prints triangles for unvisited neighbors (qh.visit_id)
 
   notes:
     must agree with printend4geom()
 */
 void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
   setT *vertices;
   facetT *neighbor, **neighborp;
   vertexT *vertex, **vertexp;
   int k;
 
   facet->visitid= qh visit_id;
   if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
     return;
   FOREACHneighbor_(facet) {
     if (neighbor->visitid == qh visit_id)
       continue;
     if (qh PRINTtransparent && !neighbor->good)
       continue;
     vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim,
                           SETindex_(facet->neighbors, neighbor), 0);
     if (qh DOintersections)
       qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
     else {
       if (qh DROPdim >= 0)
         qh_fprintf(fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",
                 facet->id, neighbor->id);
       else {
         qh printoutvar++;
         qh_fprintf(fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);
       }
       FOREACHvertex_(vertices) {
         for (k=0; k < qh hull_dim; k++) {
           if (k != qh DROPdim)
             qh_fprintf(fp, 9121, "%8.4g ", vertex->point[k]);
         }
         qh_fprintf(fp, 9122, "\n");
       }
       if (qh DROPdim >= 0)
         qh_fprintf(fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
     }
     qh_setfree(&vertices);
   }
 } /* printfacet4geom_simplicial */
 
 
 /*---------------------------------
 
   qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
     print vertices for an N-d non-simplicial facet
     triangulates each ridge to the id
 */
 void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format) {
   vertexT *vertex, **vertexp;
   ridgeT *ridge, **ridgep;
 
   if (facet->visible && qh NEWfacets)
     return;
   FOREACHridge_(facet->ridges) {
     if (format == qh_PRINTtriangles)
       qh_fprintf(fp, 9124, "%d ", qh hull_dim);
     qh_fprintf(fp, 9125, "%d ", id);
     if ((ridge->top == facet) ^ qh_ORIENTclock) {
       FOREACHvertex_(ridge->vertices)
         qh_fprintf(fp, 9126, "%d ", qh_pointid(vertex->point));
     }else {
       FOREACHvertexreverse12_(ridge->vertices)
         qh_fprintf(fp, 9127, "%d ", qh_pointid(vertex->point));
     }
     qh_fprintf(fp, 9128, "\n");
   }
 } /* printfacetNvertex_nonsimplicial */
 
 
 /*---------------------------------
 
   qh_printfacetNvertex_simplicial( fp, facet, format )
     print vertices for an N-d simplicial facet
     prints vertices for non-simplicial facets
       2-d facets (orientation preserved by qh_mergefacet2d)
       PRINToff ('o') for 4-d and higher
 */
 void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format) {
   vertexT *vertex, **vertexp;
 
   if (format == qh_PRINToff || format == qh_PRINTtriangles)
     qh_fprintf(fp, 9129, "%d ", qh_setsize(facet->vertices));
   if ((facet->toporient ^ qh_ORIENTclock)
   || (qh hull_dim > 2 && !facet->simplicial)) {
     FOREACHvertex_(facet->vertices)
       qh_fprintf(fp, 9130, "%d ", qh_pointid(vertex->point));
   }else {
     FOREACHvertexreverse12_(facet->vertices)
       qh_fprintf(fp, 9131, "%d ", qh_pointid(vertex->point));
   }
   qh_fprintf(fp, 9132, "\n");
 } /* printfacetNvertex_simplicial */
 
 
 /*---------------------------------
 
   qh_printfacetheader( fp, facet )
     prints header fields of a facet to fp
 
   notes:
     for 'f' output and debugging
     Same as QhullFacet::printHeader()
 */
 void qh_printfacetheader(FILE *fp, facetT *facet) {
   pointT *point, **pointp, *furthest;
   facetT *neighbor, **neighborp;
   realT dist;
 
   if (facet == qh_MERGEridge) {
     qh_fprintf(fp, 9133, " MERGEridge\n");
     return;
   }else if (facet == qh_DUPLICATEridge) {
     qh_fprintf(fp, 9134, " DUPLICATEridge\n");
     return;
   }else if (!facet) {
     qh_fprintf(fp, 9135, " NULLfacet\n");
     return;
   }
   qh old_randomdist= qh RANDOMdist;
   qh RANDOMdist= False;
   qh_fprintf(fp, 9136, "- f%d\n", facet->id);
   qh_fprintf(fp, 9137, "    - flags:");
   if (facet->toporient)
     qh_fprintf(fp, 9138, " top");
   else
     qh_fprintf(fp, 9139, " bottom");
   if (facet->simplicial)
     qh_fprintf(fp, 9140, " simplicial");
   if (facet->tricoplanar)
     qh_fprintf(fp, 9141, " tricoplanar");
   if (facet->upperdelaunay)
     qh_fprintf(fp, 9142, " upperDelaunay");
   if (facet->visible)
     qh_fprintf(fp, 9143, " visible");
   if (facet->newfacet)
     qh_fprintf(fp, 9144, " new");
   if (facet->tested)
     qh_fprintf(fp, 9145, " tested");
   if (!facet->good)
     qh_fprintf(fp, 9146, " notG");
   if (facet->seen)
     qh_fprintf(fp, 9147, " seen");
   if (facet->coplanar)
     qh_fprintf(fp, 9148, " coplanar");
   if (facet->mergehorizon)
     qh_fprintf(fp, 9149, " mergehorizon");
   if (facet->keepcentrum)
     qh_fprintf(fp, 9150, " keepcentrum");
   if (facet->dupridge)
     qh_fprintf(fp, 9151, " dupridge");
   if (facet->mergeridge && !facet->mergeridge2)
     qh_fprintf(fp, 9152, " mergeridge1");
   if (facet->mergeridge2)
     qh_fprintf(fp, 9153, " mergeridge2");
   if (facet->newmerge)
     qh_fprintf(fp, 9154, " newmerge");
   if (facet->flipped)
     qh_fprintf(fp, 9155, " flipped");
   if (facet->notfurthest)
     qh_fprintf(fp, 9156, " notfurthest");
   if (facet->degenerate)
     qh_fprintf(fp, 9157, " degenerate");
   if (facet->redundant)
     qh_fprintf(fp, 9158, " redundant");
   qh_fprintf(fp, 9159, "\n");
   if (facet->isarea)
     qh_fprintf(fp, 9160, "    - area: %2.2g\n", facet->f.area);
   else if (qh NEWfacets && facet->visible && facet->f.replace)
     qh_fprintf(fp, 9161, "    - replacement: f%d\n", facet->f.replace->id);
   else if (facet->newfacet) {
     if (facet->f.samecycle && facet->f.samecycle != facet)
       qh_fprintf(fp, 9162, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
   }else if (facet->tricoplanar /* !isarea */) {
     if (facet->f.triowner)
       qh_fprintf(fp, 9163, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
   }else if (facet->f.newcycle)
     qh_fprintf(fp, 9164, "    - was horizon to f%d\n", facet->f.newcycle->id);
   if (facet->nummerge)
     qh_fprintf(fp, 9165, "    - merges: %d\n", facet->nummerge);
   qh_printpointid(fp, "    - normal: ", qh hull_dim, facet->normal, -1);
   qh_fprintf(fp, 9166, "    - offset: %10.7g\n", facet->offset);
   if (qh CENTERtype == qh_ASvoronoi || facet->center)
     qh_printcenter(fp, qh_PRINTfacets, "    - center: ", facet);
 #if qh_MAXoutside
   if (facet->maxoutside > qh DISTround)
     qh_fprintf(fp, 9167, "    - maxoutside: %10.7g\n", facet->maxoutside);
 #endif
   if (!SETempty_(facet->outsideset)) {
     furthest= (pointT*)qh_setlast(facet->outsideset);
     if (qh_setsize(facet->outsideset) < 6) {
       qh_fprintf(fp, 9168, "    - outside set(furthest p%d):\n", qh_pointid(furthest));
       FOREACHpoint_(facet->outsideset)
         qh_printpoint(fp, "     ", point);
     }else if (qh_setsize(facet->outsideset) < 21) {
       qh_printpoints(fp, "    - outside set:", facet->outsideset);
     }else {
       qh_fprintf(fp, 9169, "    - outside set:  %d points.", qh_setsize(facet->outsideset));
       qh_printpoint(fp, "  Furthest", furthest);
     }
 #if !qh_COMPUTEfurthest
     qh_fprintf(fp, 9170, "    - furthest distance= %2.2g\n", facet->furthestdist);
 #endif
   }
   if (!SETempty_(facet->coplanarset)) {
     furthest= (pointT*)qh_setlast(facet->coplanarset);
     if (qh_setsize(facet->coplanarset) < 6) {
       qh_fprintf(fp, 9171, "    - coplanar set(furthest p%d):\n", qh_pointid(furthest));
       FOREACHpoint_(facet->coplanarset)
         qh_printpoint(fp, "     ", point);
     }else if (qh_setsize(facet->coplanarset) < 21) {
       qh_printpoints(fp, "    - coplanar set:", facet->coplanarset);
     }else {
       qh_fprintf(fp, 9172, "    - coplanar set:  %d points.", qh_setsize(facet->coplanarset));
       qh_printpoint(fp, "  Furthest", furthest);
     }
     zinc_(Zdistio);
     qh_distplane(furthest, facet, &dist);
     qh_fprintf(fp, 9173, "      furthest distance= %2.2g\n", dist);
   }
   qh_printvertices(fp, "    - vertices:", facet->vertices);
   qh_fprintf(fp, 9174, "    - neighboring facets:");
   FOREACHneighbor_(facet) {
     if (neighbor == qh_MERGEridge)
       qh_fprintf(fp, 9175, " MERGE");
     else if (neighbor == qh_DUPLICATEridge)
       qh_fprintf(fp, 9176, " DUP");
     else
       qh_fprintf(fp, 9177, " f%d", neighbor->id);
   }
   qh_fprintf(fp, 9178, "\n");
   qh RANDOMdist= qh old_randomdist;
 } /* printfacetheader */
 
 
 /*---------------------------------
 
   qh_printfacetridges( fp, facet )
     prints ridges of a facet to fp
 
   notes:
     ridges printed in neighbor order
     assumes the ridges exist
     for 'f' output
     same as QhullFacet::printRidges
 */
 void qh_printfacetridges(FILE *fp, facetT *facet) {
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int numridges= 0;
 
 
   if (facet->visible && qh NEWfacets) {
     qh_fprintf(fp, 9179, "    - ridges(ids may be garbage):");
     FOREACHridge_(facet->ridges)
       qh_fprintf(fp, 9180, " r%d", ridge->id);
     qh_fprintf(fp, 9181, "\n");
   }else {
     qh_fprintf(fp, 9182, "    - ridges:\n");
     FOREACHridge_(facet->ridges)
       ridge->seen= False;
     if (qh hull_dim == 3) {
       ridge= SETfirstt_(facet->ridges, ridgeT);
       while (ridge && !ridge->seen) {
         ridge->seen= True;
         qh_printridge(fp, ridge);
         numridges++;
         ridge= qh_nextridge3d(ridge, facet, NULL);
         }
     }else {
       FOREACHneighbor_(facet) {
         FOREACHridge_(facet->ridges) {
           if (otherfacet_(ridge,facet) == neighbor) {
             ridge->seen= True;
             qh_printridge(fp, ridge);
             numridges++;
           }
         }
       }
     }
     if (numridges != qh_setsize(facet->ridges)) {
       qh_fprintf(fp, 9183, "     - all ridges:");
       FOREACHridge_(facet->ridges)
         qh_fprintf(fp, 9184, " r%d", ridge->id);
         qh_fprintf(fp, 9185, "\n");
     }
     FOREACHridge_(facet->ridges) {
       if (!ridge->seen)
         qh_printridge(fp, ridge);
     }
   }
 } /* printfacetridges */
 
 /*---------------------------------
 
   qh_printfacets( fp, format, facetlist, facets, printall )
     prints facetlist and/or facet set in output format
 
   notes:
     also used for specialized formats ('FO' and summary)
     turns off 'Rn' option since want actual numbers
 */
 void qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
   facetT *facet, **facetp;
   setT *vertices;
   coordT *center;
   realT outerplane, innerplane;
 
   qh old_randomdist= qh RANDOMdist;
   qh RANDOMdist= False;
   if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
     qh_fprintf(qh ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
   if (format == qh_PRINTnone)
     ; /* print nothing */
   else if (format == qh_PRINTaverage) {
     vertices= qh_facetvertices(facetlist, facets, printall);
     center= qh_getcenter(vertices);
     qh_fprintf(fp, 9186, "%d 1\n", qh hull_dim);
     qh_printpointid(fp, NULL, qh hull_dim, center, -1);
     qh_memfree(center, qh normal_size);
     qh_settempfree(&vertices);
   }else if (format == qh_PRINTextremes) {
     if (qh DELAUNAY)
       qh_printextremes_d(fp, facetlist, facets, printall);
     else if (qh hull_dim == 2)
       qh_printextremes_2d(fp, facetlist, facets, printall);
     else
       qh_printextremes(fp, facetlist, facets, printall);
   }else if (format == qh_PRINToptions)
     qh_fprintf(fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
   else if (format == qh_PRINTpoints && !qh VORONOI)
     qh_printpoints_out(fp, facetlist, facets, printall);
   else if (format == qh_PRINTqhull)
     qh_fprintf(fp, 9188, "%s | %s\n", qh rbox_command, qh qhull_command);
   else if (format == qh_PRINTsize) {
     qh_fprintf(fp, 9189, "0\n2 ");
     qh_fprintf(fp, 9190, qh_REAL_1, qh totarea);
     qh_fprintf(fp, 9191, qh_REAL_1, qh totvol);
     qh_fprintf(fp, 9192, "\n");
   }else if (format == qh_PRINTsummary) {
     qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
     vertices= qh_facetvertices(facetlist, facets, printall);
     qh_fprintf(fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim,
                 qh num_points + qh_setsize(qh other_points),
                 qh num_vertices, qh num_facets - qh num_visible,
                 qh_setsize(vertices), numfacets, numcoplanars,
                 numfacets - numsimplicial, zzval_(Zdelvertextot),
                 numtricoplanars);
     qh_settempfree(&vertices);
     qh_outerinner(NULL, &outerplane, &innerplane);
     qh_fprintf(fp, 9194, qh_REAL_2n, outerplane, innerplane);
   }else if (format == qh_PRINTvneighbors)
     qh_printvneighbors(fp, facetlist, facets, printall);
   else if (qh VORONOI && format == qh_PRINToff)
     qh_printvoronoi(fp, format, facetlist, facets, printall);
   else if (qh VORONOI && format == qh_PRINTgeom) {
     qh_printbegin(fp, format, facetlist, facets, printall);
     qh_printvoronoi(fp, format, facetlist, facets, printall);
     qh_printend(fp, format, facetlist, facets, printall);
   }else if (qh VORONOI
   && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
     qh_printvdiagram(fp, format, facetlist, facets, printall);
   else {
     qh_printbegin(fp, format, facetlist, facets, printall);
     FORALLfacet_(facetlist)
       qh_printafacet(fp, format, facet, printall);
     FOREACHfacet_(facets)
       qh_printafacet(fp, format, facet, printall);
     qh_printend(fp, format, facetlist, facets, printall);
   }
   qh RANDOMdist= qh old_randomdist;
 } /* printfacets */
 
 
 /*---------------------------------
 
   qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
     print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
 */
 void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
                    setT *vertices, realT color[3]) {
   realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
   vertexT *vertex, **vertexp;
   int i, k;
   boolT nearzero1, nearzero2;
 
   costheta= qh_getangle(facet1->normal, facet2->normal);
   denominator= 1 - costheta * costheta;
   i= qh_setsize(vertices);
   if (qh hull_dim == 3)
     qh_fprintf(fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);
   else if (qh hull_dim == 4 && qh DROPdim >= 0)
     qh_fprintf(fp, 9196, "OFF 3 1 1 ");
   else
     qh printoutvar++;
   qh_fprintf(fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);
   mindenom= 1 / (10.0 * qh MAXabs_coord);
   FOREACHvertex_(vertices) {
     zadd_(Zdistio, 2);
     qh_distplane(vertex->point, facet1, &dist1);
     qh_distplane(vertex->point, facet2, &dist2);
     s= qh_divzero(-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
     t= qh_divzero(-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
     if (nearzero1 || nearzero2)
       s= t= 0.0;
     for (k=qh hull_dim; k--; )
       p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
     if (qh PRINTdim <= 3) {
       qh_projectdim3(p, p);
       qh_fprintf(fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
     }else
       qh_fprintf(fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
     if (nearzero1+nearzero2)
       qh_fprintf(fp, 9200, "p%d(coplanar facets)\n", qh_pointid(vertex->point));
     else
       qh_fprintf(fp, 9201, "projected p%d\n", qh_pointid(vertex->point));
   }
   if (qh hull_dim == 3)
     qh_fprintf(fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
   else if (qh hull_dim == 4 && qh DROPdim >= 0)
     qh_fprintf(fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
 } /* printhyperplaneintersection */
 
 /*---------------------------------
 
   qh_printline3geom( fp, pointA, pointB, color )
     prints a line as a VECT
     prints 0's for qh.DROPdim
 
   notes:
     if pointA == pointB,
       it's a 1 point VECT
 */
 void qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
   int k;
   realT pA[4], pB[4];
 
   qh_projectdim3(pointA, pA);
   qh_projectdim3(pointB, pB);
   if ((fabs(pA[0] - pB[0]) > 1e-3) ||
       (fabs(pA[1] - pB[1]) > 1e-3) ||
       (fabs(pA[2] - pB[2]) > 1e-3)) {
     qh_fprintf(fp, 9204, "VECT 1 2 1 2 1\n");
     for (k=0; k < 3; k++)
        qh_fprintf(fp, 9205, "%8.4g ", pB[k]);
     qh_fprintf(fp, 9206, " # p%d\n", qh_pointid(pointB));
   }else
     qh_fprintf(fp, 9207, "VECT 1 1 1 1 1\n");
   for (k=0; k < 3; k++)
     qh_fprintf(fp, 9208, "%8.4g ", pA[k]);
   qh_fprintf(fp, 9209, " # p%d\n", qh_pointid(pointA));
   qh_fprintf(fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
 }
 
 /*---------------------------------
 
   qh_printneighborhood( fp, format, facetA, facetB, printall )
     print neighborhood of one or two facets
 
   notes:
     calls qh_findgood_all()
     bumps qh.visit_id
 */
 void qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {
   facetT *neighbor, **neighborp, *facet;
   setT *facets;
 
   if (format == qh_PRINTnone)
     return;
   qh_findgood_all(qh facet_list);
   if (facetA == facetB)
     facetB= NULL;
   facets= qh_settemp(2*(qh_setsize(facetA->neighbors)+1));
   qh visit_id++;
   for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
     if (facet->visitid != qh visit_id) {
       facet->visitid= qh visit_id;
       qh_setappend(&facets, facet);
     }
     FOREACHneighbor_(facet) {
       if (neighbor->visitid == qh visit_id)
         continue;
       neighbor->visitid= qh visit_id;
       if (printall || !qh_skipfacet(neighbor))
         qh_setappend(&facets, neighbor);
     }
   }
   qh_printfacets(fp, format, NULL, facets, printall);
   qh_settempfree(&facets);
 } /* printneighborhood */
 
 /*---------------------------------
 
   qh_printpoint( fp, string, point )
   qh_printpointid( fp, string, dim, point, id )
     prints the coordinates of a point
 
   returns:
     if string is defined
       prints 'string p%d' (skips p%d if id=-1)
 
   notes:
     nop if point is NULL
     prints id unless it is undefined (-1)
     Same as QhullPoint's printPoint
 */
 void qh_printpoint(FILE *fp, const char *string, pointT *point) {
   int id= qh_pointid( point);
 
   qh_printpointid( fp, string, qh hull_dim, point, id);
 } /* printpoint */
 
 void qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id) {
   int k;
   realT r; /*bug fix*/
 
   if (!point)
     return;
   if (string) {
     qh_fprintf(fp, 9211, "%s", string);
    if (id != -1)
       qh_fprintf(fp, 9212, " p%d: ", id);
   }
   for (k=dim; k--; ) {
     r= *point++;
     if (string)
       qh_fprintf(fp, 9213, " %8.4g", r);
     else
       qh_fprintf(fp, 9214, qh_REAL_1, r);
   }
   qh_fprintf(fp, 9215, "\n");
 } /* printpointid */
 
 /*---------------------------------
 
   qh_printpoint3( fp, point )
     prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
 */
 void qh_printpoint3(FILE *fp, pointT *point) {
   int k;
   realT p[4];
 
   qh_projectdim3(point, p);
   for (k=0; k < 3; k++)
     qh_fprintf(fp, 9216, "%8.4g ", p[k]);
   qh_fprintf(fp, 9217, " # p%d\n", qh_pointid(point));
 } /* printpoint3 */
 
 /*----------------------------------------
 -printpoints- print pointids for a set of points starting at index
    see geom.c
 */
 
 /*---------------------------------
 
   qh_printpoints_out( fp, facetlist, facets, printall )
     prints vertices, coplanar/inside points, for facets by their point coordinates
     allows qh.CDDoutput
 
   notes:
     same format as qhull input
     if no coplanar/interior points,
       same order as qh_printextremes
 */
 void qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   int allpoints= qh num_points + qh_setsize(qh other_points);
   int numpoints=0, point_i, point_n;
   setT *vertices, *points;
   facetT *facet, **facetp;
   pointT *point, **pointp;
   vertexT *vertex, **vertexp;
   int id;
 
   points= qh_settemp(allpoints);
   qh_setzero(points, 0, allpoints);
   vertices= qh_facetvertices(facetlist, facets, printall);
   FOREACHvertex_(vertices) {
     id= qh_pointid(vertex->point);
     if (id >= 0)
       SETelem_(points, id)= vertex->point;
   }
   if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
     FORALLfacet_(facetlist) {
       if (!printall && qh_skipfacet(facet))
         continue;
       FOREACHpoint_(facet->coplanarset) {
         id= qh_pointid(point);
         if (id >= 0)
           SETelem_(points, id)= point;
       }
     }
     FOREACHfacet_(facets) {
       if (!printall && qh_skipfacet(facet))
         continue;
       FOREACHpoint_(facet->coplanarset) {
         id= qh_pointid(point);
         if (id >= 0)
           SETelem_(points, id)= point;
       }
     }
   }
   qh_settempfree(&vertices);
   FOREACHpoint_i_(points) {
     if (point)
       numpoints++;
   }
   if (qh CDDoutput)
     qh_fprintf(fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
              qh qhull_command, numpoints, qh hull_dim + 1);
   else
     qh_fprintf(fp, 9219, "%d\n%d\n", qh hull_dim, numpoints);
   FOREACHpoint_i_(points) {
     if (point) {
       if (qh CDDoutput)
         qh_fprintf(fp, 9220, "1 ");
       qh_printpoint(fp, NULL, point);
     }
   }
   if (qh CDDoutput)
     qh_fprintf(fp, 9221, "end\n");
   qh_settempfree(&points);
 } /* printpoints_out */
 
 
 /*---------------------------------
 
   qh_printpointvect( fp, point, normal, center, radius, color )
     prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
 */
 void qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
   realT diff[4], pointA[4];
   int k;
 
   for (k=qh hull_dim; k--; ) {
     if (center)
       diff[k]= point[k]-center[k];
     else if (normal)
       diff[k]= normal[k];
     else
       diff[k]= 0;
   }
   if (center)
     qh_normalize2(diff, qh hull_dim, True, NULL, NULL);
   for (k=qh hull_dim; k--; )
     pointA[k]= point[k]+diff[k] * radius;
   qh_printline3geom(fp, point, pointA, color);
 } /* printpointvect */
 
 /*---------------------------------
 
   qh_printpointvect2( fp, point, normal, center, radius )
     prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
 */
 void qh_printpointvect2(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
   realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
 
   qh_printpointvect(fp, point, normal, center, radius, red);
   qh_printpointvect(fp, point, normal, center, -radius, yellow);
 } /* printpointvect2 */
 
 /*---------------------------------
 
   qh_printridge( fp, ridge )
     prints the information in a ridge
 
   notes:
     for qh_printfacetridges()
     same as operator<< [QhullRidge.cpp]
 */
 void qh_printridge(FILE *fp, ridgeT *ridge) {
 
   qh_fprintf(fp, 9222, "     - r%d", ridge->id);
   if (ridge->tested)
     qh_fprintf(fp, 9223, " tested");
   if (ridge->nonconvex)
     qh_fprintf(fp, 9224, " nonconvex");
   qh_fprintf(fp, 9225, "\n");
   qh_printvertices(fp, "           vertices:", ridge->vertices);
   if (ridge->top && ridge->bottom)
     qh_fprintf(fp, 9226, "           between f%d and f%d\n",
             ridge->top->id, ridge->bottom->id);
 } /* printridge */
 
 /*---------------------------------
 
   qh_printspheres( fp, vertices, radius )
     prints 3-d vertices as OFF spheres
 
   notes:
     inflated octahedron from Stuart Levy earth/mksphere2
 */
 void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
   vertexT *vertex, **vertexp;
 
   qh printoutnum++;
   qh_fprintf(fp, 9227, "{appearance {-edge -normal normscale 0} {\n\
 INST geom {define vsphere OFF\n\
 18 32 48\n\
 \n\
 0 0 1\n\
 1 0 0\n\
 0 1 0\n\
 -1 0 0\n\
 0 -1 0\n\
 0 0 -1\n\
 0.707107 0 0.707107\n\
 0 -0.707107 0.707107\n\
 0.707107 -0.707107 0\n\
 -0.707107 0 0.707107\n\
 -0.707107 -0.707107 0\n\
 0 0.707107 0.707107\n\
 -0.707107 0.707107 0\n\
 0.707107 0.707107 0\n\
 0.707107 0 -0.707107\n\
 0 0.707107 -0.707107\n\
 -0.707107 0 -0.707107\n\
 0 -0.707107 -0.707107\n\
 \n\
 3 0 6 11\n\
 3 0 7 6 \n\
 3 0 9 7 \n\
 3 0 11 9\n\
 3 1 6 8 \n\
 3 1 8 14\n\
 3 1 13 6\n\
 3 1 14 13\n\
 3 2 11 13\n\
 3 2 12 11\n\
 3 2 13 15\n\
 3 2 15 12\n\
 3 3 9 12\n\
 3 3 10 9\n\
 3 3 12 16\n\
 3 3 16 10\n\
 3 4 7 10\n\
 3 4 8 7\n\
 3 4 10 17\n\
 3 4 17 8\n\
 3 5 14 17\n\
 3 5 15 14\n\
 3 5 16 15\n\
 3 5 17 16\n\
 3 6 13 11\n\
 3 7 8 6\n\
 3 9 10 7\n\
 3 11 12 9\n\
 3 14 8 17\n\
 3 15 13 14\n\
 3 16 12 15\n\
 3 17 10 16\n} transforms { TLIST\n");
   FOREACHvertex_(vertices) {
     qh_fprintf(fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
       radius, vertex->id, radius, radius);
     qh_printpoint3(fp, vertex->point);
     qh_fprintf(fp, 9229, "1\n");
   }
   qh_fprintf(fp, 9230, "}}}\n");
 } /* printspheres */
 
 
 /*----------------------------------------------
 -printsummary-
                 see libqhull.c
 */
 
 /*---------------------------------
 
   qh_printvdiagram( fp, format, facetlist, facets, printall )
     print voronoi diagram
       # of pairs of input sites
       #indices site1 site2 vertex1 ...
 
     sites indexed by input point id
       point 0 is the first input point
     vertices indexed by 'o' and 'p' order
       vertex 0 is the 'vertex-at-infinity'
       vertex 1 is the first Voronoi vertex
 
   see:
     qh_printvoronoi()
     qh_eachvoronoi_all()
 
   notes:
     if all facets are upperdelaunay,
       prints upper hull (furthest-site Voronoi diagram)
 */
 void qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   setT *vertices;
   int totcount, numcenters;
   boolT isLower;
   qh_RIDGE innerouter= qh_RIDGEall;
   printvridgeT printvridge= NULL;
 
   if (format == qh_PRINTvertices) {
     innerouter= qh_RIDGEall;
     printvridge= qh_printvridge;
   }else if (format == qh_PRINTinner) {
     innerouter= qh_RIDGEinner;
     printvridge= qh_printvnorm;
   }else if (format == qh_PRINTouter) {
     innerouter= qh_RIDGEouter;
     printvridge= qh_printvnorm;
   }else {
     qh_fprintf(qh ferr, 6219, "Qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   vertices= qh_markvoronoi(facetlist, facets, printall, &isLower, &numcenters);
   totcount= qh_printvdiagram2(NULL, NULL, vertices, innerouter, False);
   qh_fprintf(fp, 9231, "%d\n", totcount);
   totcount= qh_printvdiagram2(fp, printvridge, vertices, innerouter, True /* inorder*/);
   qh_settempfree(&vertices);
 #if 0  /* for testing qh_eachvoronoi_all */
   qh_fprintf(fp, 9232, "\n");
   totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
   qh_fprintf(fp, 9233, "%d\n", totcount);
 #endif
 } /* printvdiagram */
 
 /*---------------------------------
 
   qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
     visit all pairs of input sites (vertices) for selected Voronoi vertices
     vertices may include NULLs
 
   innerouter:
     qh_RIDGEall   print inner ridges(bounded) and outer ridges(unbounded)
     qh_RIDGEinner print only inner ridges
     qh_RIDGEouter print only outer ridges
 
   inorder:
     print 3-d Voronoi vertices in order
 
   assumes:
     qh_markvoronoi marked facet->visitid for Voronoi vertices
     all facet->seen= False
     all facet->seen2= True
 
   returns:
     total number of Voronoi ridges
     if printvridge,
       calls printvridge( fp, vertex, vertexA, centers) for each ridge
       [see qh_eachvoronoi()]
 
   see:
     qh_eachvoronoi_all()
 */
 int qh_printvdiagram2(FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
   int totcount= 0;
   int vertex_i, vertex_n;
   vertexT *vertex;
 
   FORALLvertices
     vertex->seen= False;
   FOREACHvertex_i_(vertices) {
     if (vertex) {
       if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
         continue;
       totcount += qh_eachvoronoi(fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
     }
   }
   return totcount;
 } /* printvdiagram2 */
 
 /*---------------------------------
 
   qh_printvertex( fp, vertex )
     prints the information in a vertex
     Duplicated as operator<< [QhullVertex.cpp]
 */
 void qh_printvertex(FILE *fp, vertexT *vertex) {
   pointT *point;
   int k, count= 0;
   facetT *neighbor, **neighborp;
   realT r; /*bug fix*/
 
   if (!vertex) {
     qh_fprintf(fp, 9234, "  NULLvertex\n");
     return;
   }
   qh_fprintf(fp, 9235, "- p%d(v%d):", qh_pointid(vertex->point), vertex->id);
   point= vertex->point;
   if (point) {
     for (k=qh hull_dim; k--; ) {
       r= *point++;
       qh_fprintf(fp, 9236, " %5.2g", r);
     }
   }
   if (vertex->deleted)
     qh_fprintf(fp, 9237, " deleted");
   if (vertex->delridge)
     qh_fprintf(fp, 9238, " ridgedeleted");
   qh_fprintf(fp, 9239, "\n");
   if (vertex->neighbors) {
     qh_fprintf(fp, 9240, "  neighbors:");
     FOREACHneighbor_(vertex) {
       if (++count % 100 == 0)
         qh_fprintf(fp, 9241, "\n     ");
       qh_fprintf(fp, 9242, " f%d", neighbor->id);
     }
     qh_fprintf(fp, 9243, "\n");
   }
 } /* printvertex */
 
 
 /*---------------------------------
 
   qh_printvertexlist( fp, string, facetlist, facets, printall )
     prints vertices used by a facetlist or facet set
     tests qh_skipfacet() if !printall
 */
 void qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist,
                          setT *facets, boolT printall) {
   vertexT *vertex, **vertexp;
   setT *vertices;
 
   vertices= qh_facetvertices(facetlist, facets, printall);
   qh_fprintf(fp, 9244, "%s", string);
   FOREACHvertex_(vertices)
     qh_printvertex(fp, vertex);
   qh_settempfree(&vertices);
 } /* printvertexlist */
 
 
 /*---------------------------------
 
   qh_printvertices( fp, string, vertices )
     prints vertices in a set
     duplicated as printVertexSet [QhullVertex.cpp]
 */
 void qh_printvertices(FILE *fp, const char* string, setT *vertices) {
   vertexT *vertex, **vertexp;
 
   qh_fprintf(fp, 9245, "%s", string);
   FOREACHvertex_(vertices)
     qh_fprintf(fp, 9246, " p%d(v%d)", qh_pointid(vertex->point), vertex->id);
   qh_fprintf(fp, 9247, "\n");
 } /* printvertices */
 
 /*---------------------------------
 
   qh_printvneighbors( fp, facetlist, facets, printall )
     print vertex neighbors of vertices in facetlist and facets ('FN')
 
   notes:
     qh_countfacets clears facet->visitid for non-printed facets
 
   design:
     collect facet count and related statistics
     if necessary, build neighbor sets for each vertex
     collect vertices in facetlist and facets
     build a point array for point->vertex and point->coplanar facet
     for each point
       list vertex neighbors or coplanar facet
 */
 void qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
   int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
   setT *vertices, *vertex_points, *coplanar_points;
   int numpoints= qh num_points + qh_setsize(qh other_points);
   vertexT *vertex, **vertexp;
   int vertex_i, vertex_n;
   facetT *facet, **facetp, *neighbor, **neighborp;
   pointT *point, **pointp;
 
   qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
   qh_fprintf(fp, 9248, "%d\n", numpoints);
   qh_vertexneighbors();
   vertices= qh_facetvertices(facetlist, facets, printall);
   vertex_points= qh_settemp(numpoints);
   coplanar_points= qh_settemp(numpoints);
   qh_setzero(vertex_points, 0, numpoints);
   qh_setzero(coplanar_points, 0, numpoints);
   FOREACHvertex_(vertices)
     qh_point_add(vertex_points, vertex->point, vertex);
   FORALLfacet_(facetlist) {
     FOREACHpoint_(facet->coplanarset)
       qh_point_add(coplanar_points, point, facet);
   }
   FOREACHfacet_(facets) {
     FOREACHpoint_(facet->coplanarset)
       qh_point_add(coplanar_points, point, facet);
   }
   FOREACHvertex_i_(vertex_points) {
     if (vertex) {
       numneighbors= qh_setsize(vertex->neighbors);
       qh_fprintf(fp, 9249, "%d", numneighbors);
       if (qh hull_dim == 3)
         qh_order_vertexneighbors(vertex);
       else if (qh hull_dim >= 4)
         qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,
              sizeof(facetT *), qh_compare_facetvisit);
       FOREACHneighbor_(vertex)
         qh_fprintf(fp, 9250, " %d",
                  neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);
       qh_fprintf(fp, 9251, "\n");
     }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
       qh_fprintf(fp, 9252, "1 %d\n",
                   facet->visitid ? facet->visitid - 1 : 0 - facet->id);
     else
       qh_fprintf(fp, 9253, "0\n");
   }
   qh_settempfree(&coplanar_points);
   qh_settempfree(&vertex_points);
   qh_settempfree(&vertices);
 } /* printvneighbors */
 
 /*---------------------------------
 
   qh_printvoronoi( fp, format, facetlist, facets, printall )
     print voronoi diagram in 'o' or 'G' format
     for 'o' format
       prints voronoi centers for each facet and for infinity
       for each vertex, lists ids of printed facets or infinity
       assumes facetlist and facets are disjoint
     for 'G' format
       prints an OFF object
       adds a 0 coordinate to center
       prints infinity but does not list in vertices
 
   see:
     qh_printvdiagram()
 
   notes:
     if 'o',
       prints a line for each point except "at-infinity"
     if all facets are upperdelaunay,
       reverses lower and upper hull
 */
 void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
   facetT *facet, **facetp, *neighbor, **neighborp;
   setT *vertices;
   vertexT *vertex;
   boolT isLower;
   unsigned int numfacets= (unsigned int) qh num_facets;
 
   vertices= qh_markvoronoi(facetlist, facets, printall, &isLower, &numcenters);
   FOREACHvertex_i_(vertices) {
     if (vertex) {
       numvertices++;
       numneighbors = numinf = 0;
       FOREACHneighbor_(vertex) {
         if (neighbor->visitid == 0)
           numinf= 1;
         else if (neighbor->visitid < numfacets)
           numneighbors++;
       }
       if (numinf && !numneighbors) {
         SETelem_(vertices, vertex_i)= NULL;
         numvertices--;
       }
     }
   }
   if (format == qh_PRINTgeom)
     qh_fprintf(fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
                 numcenters, numvertices);
   else
     qh_fprintf(fp, 9255, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
   if (format == qh_PRINTgeom) {
     for (k=qh hull_dim-1; k--; )
       qh_fprintf(fp, 9256, qh_REAL_1, 0.0);
     qh_fprintf(fp, 9257, " 0 # infinity not used\n");
   }else {
     for (k=qh hull_dim-1; k--; )
       qh_fprintf(fp, 9258, qh_REAL_1, qh_INFINITE);
     qh_fprintf(fp, 9259, "\n");
   }
   FORALLfacet_(facetlist) {
     if (facet->visitid && facet->visitid < numfacets) {
       if (format == qh_PRINTgeom)
         qh_fprintf(fp, 9260, "# %d f%d\n", vid++, facet->id);
       qh_printcenter(fp, format, NULL, facet);
     }
   }
   FOREACHfacet_(facets) {
     if (facet->visitid && facet->visitid < numfacets) {
       if (format == qh_PRINTgeom)
         qh_fprintf(fp, 9261, "# %d f%d\n", vid++, facet->id);
       qh_printcenter(fp, format, NULL, facet);
     }
   }
   FOREACHvertex_i_(vertices) {
     numneighbors= 0;
     numinf=0;
     if (vertex) {
       if (qh hull_dim == 3)
         qh_order_vertexneighbors(vertex);
       else if (qh hull_dim >= 4)
         qsort(SETaddr_(vertex->neighbors, facetT),
              (size_t)qh_setsize(vertex->neighbors),
              sizeof(facetT *), qh_compare_facetvisit);
       FOREACHneighbor_(vertex) {
         if (neighbor->visitid == 0)
           numinf= 1;
         else if (neighbor->visitid < numfacets)
           numneighbors++;
       }
     }
     if (format == qh_PRINTgeom) {
       if (vertex) {
         qh_fprintf(fp, 9262, "%d", numneighbors);
         FOREACHneighbor_(vertex) {
           if (neighbor->visitid && neighbor->visitid < numfacets)
             qh_fprintf(fp, 9263, " %d", neighbor->visitid);
         }
         qh_fprintf(fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);
       }else
         qh_fprintf(fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);
     }else {
       if (numinf)
         numneighbors++;
       qh_fprintf(fp, 9266, "%d", numneighbors);
       if (vertex) {
         FOREACHneighbor_(vertex) {
           if (neighbor->visitid == 0) {
             if (numinf) {
               numinf= 0;
               qh_fprintf(fp, 9267, " %d", neighbor->visitid);
             }
           }else if (neighbor->visitid < numfacets)
             qh_fprintf(fp, 9268, " %d", neighbor->visitid);
         }
       }
       qh_fprintf(fp, 9269, "\n");
     }
   }
   if (format == qh_PRINTgeom)
     qh_fprintf(fp, 9270, "}\n");
   qh_settempfree(&vertices);
 } /* printvoronoi */
 
 /*---------------------------------
 
   qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
     print one separating plane of the Voronoi diagram for a pair of input sites
     unbounded==True if centers includes vertex-at-infinity
 
   assumes:
     qh_ASvoronoi and qh_vertexneighbors() already set
 
   note:
     parameter unbounded is UNUSED by this callback
 
   see:
     qh_printvdiagram()
     qh_eachvoronoi()
 */
 void qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
   pointT *normal;
   realT offset;
   int k;
   QHULL_UNUSED(unbounded);
 
   normal= qh_detvnorm(vertex, vertexA, centers, &offset);
   qh_fprintf(fp, 9271, "%d %d %d ",
       2+qh hull_dim, qh_pointid(vertex->point), qh_pointid(vertexA->point));
   for (k=0; k< qh hull_dim-1; k++)
     qh_fprintf(fp, 9272, qh_REAL_1, normal[k]);
   qh_fprintf(fp, 9273, qh_REAL_1, offset);
   qh_fprintf(fp, 9274, "\n");
 } /* printvnorm */
 
 /*---------------------------------
 
   qh_printvridge( fp, vertex, vertexA, centers, unbounded )
     print one ridge of the Voronoi diagram for a pair of input sites
     unbounded==True if centers includes vertex-at-infinity
 
   see:
     qh_printvdiagram()
 
   notes:
     the user may use a different function
     parameter unbounded is UNUSED
 */
 void qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
   facetT *facet, **facetp;
   QHULL_UNUSED(unbounded);
 
   qh_fprintf(fp, 9275, "%d %d %d", qh_setsize(centers)+2,
        qh_pointid(vertex->point), qh_pointid(vertexA->point));
   FOREACHfacet_(centers)
     qh_fprintf(fp, 9276, " %d", facet->visitid);
   qh_fprintf(fp, 9277, "\n");
 } /* printvridge */
 
 /*---------------------------------
 
   qh_projectdim3( source, destination )
     project 2-d 3-d or 4-d point to a 3-d point
     uses qh.DROPdim and qh.hull_dim
     source and destination may be the same
 
   notes:
     allocate 4 elements to destination just in case
 */
 void qh_projectdim3(pointT *source, pointT *destination) {
   int i,k;
 
   for (k=0, i=0; k < qh hull_dim; k++) {
     if (qh hull_dim == 4) {
       if (k != qh DROPdim)
         destination[i++]= source[k];
     }else if (k == qh DROPdim)
       destination[i++]= 0;
     else
       destination[i++]= source[k];
   }
   while (i < 3)
     destination[i++]= 0.0;
 } /* projectdim3 */
 
 /*---------------------------------
 
   qh_readfeasible( dim, curline )
     read feasible point from current line and qh.fin
 
   returns:
     number of lines read from qh.fin
     sets qh.FEASIBLEpoint with malloc'd coordinates
 
   notes:
     checks for qh.HALFspace
     assumes dim > 1
 
   see:
     qh_setfeasible
 */
 int qh_readfeasible(int dim, const char *curline) {
   boolT isfirst= True;
   int linecount= 0, tokcount= 0;
   const char *s;
   char *t, firstline[qh_MAXfirst+1];
   coordT *coords, value;
 
   if (!qh HALFspace) {
     qh_fprintf(qh ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (qh feasible_string)
     qh_fprintf(qh ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
   if (!(qh feasible_point= (coordT*)qh_malloc(dim* sizeof(coordT)))) {
     qh_fprintf(qh ferr, 6071, "qhull error: insufficient memory for feasible point\n");
     qh_errexit(qh_ERRmem, NULL, NULL);
   }
   coords= qh feasible_point;
   while ((s= (isfirst ?  curline : fgets(firstline, qh_MAXfirst, qh fin)))) {
     if (isfirst)
       isfirst= False;
     else
       linecount++;
     while (*s) {
       while (isspace(*s))
         s++;
       value= qh_strtod(s, &t);
       if (s == t)
         break;
       s= t;
       *(coords++)= value;
       if (++tokcount == dim) {
         while (isspace(*s))
           s++;
         qh_strtod(s, &t);
         if (s != t) {
           qh_fprintf(qh ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
                s);
           qh_errexit(qh_ERRinput, NULL, NULL);
         }
         return linecount;
       }
     }
   }
   qh_fprintf(qh ferr, 6073, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
            tokcount, dim);
   qh_errexit(qh_ERRinput, NULL, NULL);
   return 0;
 } /* readfeasible */
 
 /*---------------------------------
 
   qh_readpoints( numpoints, dimension, ismalloc )
     read points from qh.fin into qh.first_point, qh.num_points
     qh.fin is lines of coordinates, one per vertex, first line number of points
     if 'rbox D4',
       gives message
     if qh.ATinfinity,
       adds point-at-infinity for Delaunay triangulations
 
   returns:
     number of points, array of point coordinates, dimension, ismalloc True
     if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
         and clears qh.PROJECTdelaunay
     if qh.HALFspace, reads optional feasible point, reads halfspaces,
         converts to dual.
 
   for feasible point in "cdd format" in 3-d:
     3 1
     coordinates
     comments
     begin
     n 4 real/integer
     ...
     end
 
   notes:
     dimension will change in qh_initqhull_globals if qh.PROJECTinput
     uses malloc() since qh_mem not initialized
     FIXUP QH11012: qh_readpoints needs rewriting, too long
 */
 coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
   coordT *points, *coords, *infinity= NULL;
   realT paraboloid, maxboloid= -REALmax, value;
   realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
   char *s= 0, *t, firstline[qh_MAXfirst+1];
   int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
   int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
   int tokcount= 0, linecount=0, maxcount, coordcount=0;
   boolT islong, isfirst= True, wasbegin= False;
   boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
 
   if (qh CDDinput) {
     while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
       linecount++;
       if (qh HALFspace && linecount == 1 && isdigit(*s)) {
         dimfeasible= qh_strtol(s, &s);
         while (isspace(*s))
           s++;
         if (qh_strtol(s, &s) == 1)
           linecount += qh_readfeasible(dimfeasible, s);
         else
           dimfeasible= 0;
       }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))
         break;
       else if (!*qh rbox_command)
         strncat(qh rbox_command, s, sizeof(qh rbox_command)-1);
     }
     if (!s) {
       qh_fprintf(qh ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
   }
   while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
     linecount++;
     if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))
       wasbegin= True;
     while (*s) {
       while (isspace(*s))
         s++;
       if (!*s)
         break;
       if (!isdigit(*s)) {
         if (!*qh rbox_command) {
           strncat(qh rbox_command, s, sizeof(qh rbox_command)-1);
           firsttext= linecount;
         }
         break;
       }
       if (!diminput)
         diminput= qh_strtol(s, &s);
       else {
         numinput= qh_strtol(s, &s);
         if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
           linecount += qh_readfeasible(diminput, s); /* checks if ok */
           dimfeasible= diminput;
           diminput= numinput= 0;
         }else
           break;
       }
     }
   }
   if (!s) {
     qh_fprintf(qh ferr, 6075, "qhull input error: short input file.  Did not find dimension and number of points\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (diminput > numinput) {
     tempi= diminput;    /* exchange dim and n, e.g., for cdd input format */
     diminput= numinput;
     numinput= tempi;
   }
   if (diminput < 2) {
     qh_fprintf(qh ferr, 6220,"qhull input error: dimension %d(first number) should be at least 2\n",
             diminput);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (isdelaunay) {
     qh PROJECTdelaunay= False;
     if (qh CDDinput)
       *dimension= diminput;
     else
       *dimension= diminput+1;
     *numpoints= numinput;
     if (qh ATinfinity)
       (*numpoints)++;
   }else if (qh HALFspace) {
     *dimension= diminput - 1;
     *numpoints= numinput;
     if (diminput < 3) {
       qh_fprintf(qh ferr, 6221,"qhull input error: dimension %d(first number, includes offset) should be at least 3 for halfspaces\n",
             diminput);
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     if (dimfeasible) {
       if (dimfeasible != *dimension) {
         qh_fprintf(qh ferr, 6222,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
           dimfeasible, diminput);
         qh_errexit(qh_ERRinput, NULL, NULL);
       }
     }else
       qh_setfeasible(*dimension);
   }else {
     if (qh CDDinput)
       *dimension= diminput-1;
     else
       *dimension= diminput;
     *numpoints= numinput;
   }
   qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
   if (qh HALFspace) {
     qh half_space= coordp= (coordT*)qh_malloc(qh normal_size + sizeof(coordT));
     if (qh CDDinput) {
       offsetp= qh half_space;
       normalp= offsetp + 1;
     }else {
       normalp= qh half_space;
       offsetp= normalp + *dimension;
     }
   }
   qh maxline= diminput * (qh_REALdigits + 5);
   maximize_(qh maxline, 500);
   qh line= (char*)qh_malloc((qh maxline+1) * sizeof(char));
   *ismalloc= True;  /* use malloc since memory not setup */
   coords= points= qh temp_malloc=
         (coordT*)qh_malloc((*numpoints)*(*dimension)*sizeof(coordT));
   if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
     qh_fprintf(qh ferr, 6076, "qhull error: insufficient memory to read %d points\n",
             numinput);
     qh_errexit(qh_ERRmem, NULL, NULL);
   }
   if (isdelaunay && qh ATinfinity) {
     infinity= points + numinput * (*dimension);
     for (k= (*dimension) - 1; k--; )
       infinity[k]= 0.0;
   }
   maxcount= numinput * diminput;
   paraboloid= 0.0;
   while ((s= (isfirst ?  s : fgets(qh line, qh maxline, qh fin)))) {
     if (!isfirst) {
       linecount++;
       if (*s == 'e' || *s == 'E') {
         if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {
           if (qh CDDinput )
             break;
           else if (wasbegin)
             qh_fprintf(qh ferr, 7058, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
         }
       }
     }
     islong= False;
     while (*s) {
       while (isspace(*s))
         s++;
       value= qh_strtod(s, &t);
       if (s == t) {
         if (!*qh rbox_command)
          strncat(qh rbox_command, s, sizeof(qh rbox_command)-1);
         if (*s && !firsttext)
           firsttext= linecount;
         if (!islong && !firstshort && coordcount)
           firstshort= linecount;
         break;
       }
       if (!firstpoint)
         firstpoint= linecount;
       s= t;
       if (++tokcount > maxcount)
         continue;
       if (qh HALFspace) {
         if (qh CDDinput)
           *(coordp++)= -value; /* both coefficients and offset */
         else
           *(coordp++)= value;
       }else {
         *(coords++)= value;
         if (qh CDDinput && !coordcount) {
           if (value != 1.0) {
             qh_fprintf(qh ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
                    linecount);
             qh_errexit(qh_ERRinput, NULL, NULL);
           }
           coords--;
         }else if (isdelaunay) {
           paraboloid += value * value;
           if (qh ATinfinity) {
             if (qh CDDinput)
               infinity[coordcount-1] += value;
             else
               infinity[coordcount] += value;
           }
         }
       }
       if (++coordcount == diminput) {
         coordcount= 0;
         if (isdelaunay) {
           *(coords++)= paraboloid;
           maximize_(maxboloid, paraboloid);
           paraboloid= 0.0;
         }else if (qh HALFspace) {
           if (!qh_sethalfspace(*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
             qh_fprintf(qh ferr, 8048, "The halfspace was on line %d\n", linecount);
             if (wasbegin)
               qh_fprintf(qh ferr, 8049, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
             qh_errexit(qh_ERRinput, NULL, NULL);
           }
           coordp= qh half_space;
         }
         while (isspace(*s))
           s++;
         if (*s) {
           islong= True;
           if (!firstlong)
             firstlong= linecount;
         }
       }
     }
     if (!islong && !firstshort && coordcount)
       firstshort= linecount;
     if (!isfirst && s - qh line >= qh maxline) {
       qh_fprintf(qh ferr, 6078, "qhull input error: line %d contained more than %d characters\n",
               linecount, (int) (s - qh line));   /* WARN64 */
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     isfirst= False;
   }
   if (tokcount != maxcount) {
     newnum= fmin_(numinput, tokcount/diminput);
     qh_fprintf(qh ferr, 7073,"\
 qhull warning: instead of %d %d-dimensional points, input contains\n\
 %d points and %d extra coordinates.  Line %d is the first\npoint",
        numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
     if (firsttext)
       qh_fprintf(qh ferr, 8051, ", line %d is the first comment", firsttext);
     if (firstshort)
       qh_fprintf(qh ferr, 8052, ", line %d is the first short\nline", firstshort);
     if (firstlong)
       qh_fprintf(qh ferr, 8053, ", line %d is the first long line", firstlong);
     qh_fprintf(qh ferr, 8054, ".  Continue with %d points.\n", newnum);
     numinput= newnum;
     if (isdelaunay && qh ATinfinity) {
       for (k= tokcount % diminput; k--; )
         infinity[k] -= *(--coords);
       *numpoints= newnum+1;
     }else {
       coords -= tokcount % diminput;
       *numpoints= newnum;
     }
   }
   if (isdelaunay && qh ATinfinity) {
     for (k= (*dimension) -1; k--; )
       infinity[k] /= numinput;
     if (coords == infinity)
       coords += (*dimension) -1;
     else {
       for (k=0; k < (*dimension) -1; k++)
         *(coords++)= infinity[k];
     }
     *(coords++)= maxboloid * 1.1;
   }
   if (qh rbox_command[0]) {
     qh rbox_command[strlen(qh rbox_command)-1]= '\0';
     if (!strcmp(qh rbox_command, "./rbox D4"))
       qh_fprintf(qh ferr, 8055, "\n\
 This is the qhull test case.  If any errors or core dumps occur,\n\
 recompile qhull with 'make new'.  If errors still occur, there is\n\
 an incompatibility.  You should try a different compiler.  You can also\n\
 change the choices in user.h.  If you discover the source of the problem,\n\
 please send mail to qhull_bug@qhull.org.\n\
 \n\
 Type 'qhull' for a short list of options.\n");
   }
   qh_free(qh line);
   qh line= NULL;
   if (qh half_space) {
     qh_free(qh half_space);
     qh half_space= NULL;
   }
   qh temp_malloc= NULL;
   trace1((qh ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",
           numinput, diminput));
   return(points);
 } /* readpoints */
 
 
 /*---------------------------------
 
   qh_setfeasible( dim )
     set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
 
   notes:
     "n,n,n" already checked by qh_initflags()
     see qh_readfeasible()
 */
 void qh_setfeasible(int dim) {
   int tokcount= 0;
   char *s;
   coordT *coords, value;
 
   if (!(s= qh feasible_string)) {
     qh_fprintf(qh ferr, 6223, "\
 qhull input error: halfspace intersection needs a feasible point.\n\
 Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (!(qh feasible_point= (pointT*)qh_malloc(dim * sizeof(coordT)))) {
     qh_fprintf(qh ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");
     qh_errexit(qh_ERRmem, NULL, NULL);
   }
   coords= qh feasible_point;
   while (*s) {
     value= qh_strtod(s, &s);
     if (++tokcount > dim) {
       qh_fprintf(qh ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
           qh feasible_string, dim);
       break;
     }
     *(coords++)= value;
     if (*s)
       s++;
   }
   while (++tokcount <= dim)
     *(coords++)= 0.0;
 } /* setfeasible */
 
 /*---------------------------------
 
   qh_skipfacet( facet )
     returns 'True' if this facet is not to be printed
 
   notes:
     based on the user provided slice thresholds and 'good' specifications
 */
 boolT qh_skipfacet(facetT *facet) {
   facetT *neighbor, **neighborp;
 
   if (qh PRINTneighbors) {
     if (facet->good)
       return !qh PRINTgood;
     FOREACHneighbor_(facet) {
       if (neighbor->good)
         return False;
     }
     return True;
   }else if (qh PRINTgood)
     return !facet->good;
   else if (!facet->normal)
     return True;
   return(!qh_inthresholds(facet->normal, NULL));
 } /* skipfacet */
 
 /*---------------------------------
 
   qh_skipfilename( string )
     returns pointer to character after filename
 
   notes:
     skips leading spaces
     ends with spacing or eol
     if starts with ' or " ends with the same, skipping \' or \"
     For qhull, qh_argv_to_command() only uses double quotes
 */
 char *qh_skipfilename(char *filename) {
   char *s= filename;  /* non-const due to return */
   char c;
 
   while (*s && isspace(*s))
     s++;
   c= *s++;
   if (c == '\0') {
     qh_fprintf(qh ferr, 6204, "qhull input error: filename expected, none found.\n");
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   if (c == '\'' || c == '"') {
     while (*s !=c || s[-1] == '\\') {
       if (!*s) {
         qh_fprintf(qh ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);
         qh_errexit(qh_ERRinput, NULL, NULL);
       }
       s++;
     }
     s++;
   }
   else while (*s && !isspace(*s))
       s++;
   return s;
 } /* skipfilename */
 
diff --git a/src/libqhull/io.h b/src/libqhull/io.h
index 0a912bc..5f41125 100644
--- a/src/libqhull/io.h
+++ b/src/libqhull/io.h
@@ -1,159 +1,159 @@
 /*
  ---------------------------------
 
    io.h
    declarations of Input/Output functions
 
    see README, libqhull.h and io.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/io.h#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/io.h#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFio
 #define qhDEFio 1
 
 #include "libqhull.h"
 
 /*============ constants and flags ==================*/
 
 /*----------------------------------
 
   qh_MAXfirst
     maximum length of first two lines of stdin
 */
 #define qh_MAXfirst  200
 
 /*----------------------------------
 
   qh_MINradius
     min radius for Gp and Gv, fraction of maxcoord
 */
 #define qh_MINradius 0.02
 
 /*----------------------------------
 
   qh_GEOMepsilon
     adjust outer planes for 'lines closer' and geomview roundoff.
     This prevents bleed through.
 */
 #define qh_GEOMepsilon 2e-3
 
 /*----------------------------------
 
   qh_WHITESPACE
     possible values of white space
 */
 #define qh_WHITESPACE " \n\t\v\r\f"
 
 
 /*----------------------------------
 
   qh_RIDGE
     to select which ridges to print in qh_eachvoronoi
 */
 typedef enum
 {
     qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
 }
 qh_RIDGE;
 
 /*----------------------------------
 
   printvridgeT
     prints results of qh_printvdiagram
 
   see:
     qh_printvridge for an example
 */
 typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
 
 /*============== -prototypes in alphabetical order =========*/
 
 void    qh_dfacet(unsigned id);
 void    qh_dvertex(unsigned id);
 int     qh_compare_facetarea(const void *p1, const void *p2);
 int     qh_compare_facetmerge(const void *p1, const void *p2);
 int     qh_compare_facetvisit(const void *p1, const void *p2);
 int     qh_compare_vertexpoint(const void *p1, const void *p2); /* not used, not in libqhull_r.h */
 void    qh_copyfilename(char *filename, int size, const char* source, int length);
 void    qh_countfacets(facetT *facetlist, setT *facets, boolT printall,
               int *numfacetsp, int *numsimplicialp, int *totneighborsp,
               int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
 pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
 setT   *qh_detvridge(vertexT *vertex);
 setT   *qh_detvridge3(vertexT *atvertex, vertexT *vertex);
 int     qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
 int     qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder);
 void    qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
 setT   *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets);
 void    qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane);
 void    qh_markkeep(facetT *facetlist);
 setT   *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp);
 void    qh_order_vertexneighbors(vertexT *vertex);
 void    qh_prepare_output(void);
 void    qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall);
 void    qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet);
 void    qh_printcentrum(FILE *fp, facetT *facet, realT radius);
 void    qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printend4geom(FILE *fp, facetT *facet, int *num, boolT printall);
 void    qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printfacet(FILE *fp, facetT *facet);
 void    qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
 void    qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
                                facetT *facet, realT offset, realT color[3]);
 void    qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
 void    qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
 void    qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format);
 void    qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format);
 void    qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format);
 void    qh_printfacetheader(FILE *fp, facetT *facet);
 void    qh_printfacetridges(FILE *fp, facetT *facet);
 void    qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
                    setT *vertices, realT color[3]);
 void    qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
 void    qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
 void    qh_printpoint(FILE *fp, const char *string, pointT *point);
 void    qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id);
 void    qh_printpoint3(FILE *fp, pointT *point);
 void    qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
 void    qh_printpointvect2(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
 void    qh_printridge(FILE *fp, ridgeT *ridge);
 void    qh_printspheres(FILE *fp, setT *vertices, realT radius);
 void    qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 int     qh_printvdiagram2(FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
 void    qh_printvertex(FILE *fp, vertexT *vertex);
 void    qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist,
                          setT *facets, boolT printall);
 void    qh_printvertices(FILE *fp, const char* string, setT *vertices);
 void    qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall);
 void    qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
 void    qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
 void    qh_produce_output(void);
 void    qh_produce_output2(void);
 void    qh_projectdim3(pointT *source, pointT *destination);
 int     qh_readfeasible(int dim, const char *curline);
 coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
 void    qh_setfeasible(int dim);
 boolT   qh_skipfacet(facetT *facet);
 char   *qh_skipfilename(char *filename);
 
 #endif /* qhDEFio */
diff --git a/src/libqhull/libqhull.c b/src/libqhull/libqhull.c
index df82f3d..44eda27 100644
--- a/src/libqhull/libqhull.c
+++ b/src/libqhull/libqhull.c
@@ -1,1401 +1,1401 @@
 /*
  ---------------------------------
 
    libqhull.c
    Quickhull algorithm for convex hulls
 
    qhull() and top-level routines
 
    see qh-qhull.htm, libqhull.h, unix.c
 
    see qhull_a.h for internal functions
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/libqhull.c#5 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/libqhull.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_a.h"
 
 /*============= functions in alphabetic order after qhull() =======*/
 
 /*---------------------------------
 
   qh_qhull()
     compute DIM3 convex hull of qh.num_points starting at qh.first_point
     qh contains all global options and variables
 
   returns:
     returns polyhedron
       qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,
 
     returns global variables
       qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex
 
     returns precision constants
       qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge
 
   notes:
     unless needed for output
       qh.max_vertex and qh.min_vertex are max/min due to merges
 
   see:
     to add individual points to either qh.num_points
       use qh_addpoint()
 
     if qh.GETarea
       qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()
 
   design:
     record starting time
     initialize hull and partition points
     build convex hull
     unless early termination
       update facet->maxoutside for vertices, coplanar, and near-inside points
     error if temporary sets exist
     record end time
 */
 
 void qh_qhull(void) {
   int numoutside;
 
   qh hulltime= qh_CPUclock;
   if (qh RERUN || qh JOGGLEmax < REALmax/2)
     qh_build_withrestart();
   else {
     qh_initbuild();
     qh_buildhull();
   }
   if (!qh STOPpoint && !qh STOPcone) {
     if (qh ZEROall_ok && !qh TESTvneighbors && qh MERGEexact)
       qh_checkzero( qh_ALL);
     if (qh ZEROall_ok && !qh TESTvneighbors && !qh WAScoplanar) {
       trace2((qh ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
       qh DOcheckmax= False;
     }else {
       if (qh MERGEexact || (qh hull_dim > qh_DIMreduceBuild && qh PREmerge))
         qh_postmerge("First post-merge", qh premerge_centrum, qh premerge_cos,
              (qh POSTmerge ? False : qh TESTvneighbors));
       else if (!qh POSTmerge && qh TESTvneighbors)
         qh_postmerge("For testing vertex neighbors", qh premerge_centrum,
              qh premerge_cos, True);
       if (qh POSTmerge)
         qh_postmerge("For post-merging", qh postmerge_centrum,
              qh postmerge_cos, qh TESTvneighbors);
       if (qh visible_list == qh facet_list) { /* i.e., merging done */
         qh findbestnew= True;
         qh_partitionvisible(/*qh.visible_list*/ !qh_ALL, &numoutside);
         qh findbestnew= False;
         qh_deletevisible(/*qh.visible_list*/);
         qh_resetlists(False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
       }
     }
     if (qh DOcheckmax){
       if (qh REPORTfreq) {
         qh_buildtracing(NULL, NULL);
         qh_fprintf(qh ferr, 8115, "\nTesting all coplanar points.\n");
       }
       qh_check_maxout();
     }
     if (qh KEEPnearinside && !qh maxoutdone)
       qh_nearcoplanar();
   }
   if (qh_setsize(qhmem.tempstack) != 0) {
     qh_fprintf(qh ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d)\n",
              qh_setsize(qhmem.tempstack));
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   qh hulltime= qh_CPUclock - qh hulltime;
   qh QHULLfinished= True;
   trace1((qh ferr, 1036, "Qhull: algorithm completed\n"));
 } /* qhull */
 
 /*---------------------------------
 
   qh_addpoint( furthest, facet, checkdist )
     add point (usually furthest point) above facet to hull
     if checkdist,
       check that point is above facet.
       if point is not outside of the hull, uses qh_partitioncoplanar()
       assumes that facet is defined by qh_findbestfacet()
     else if facet specified,
       assumes that point is above facet (major damage if below)
     for Delaunay triangulations,
       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
 
   returns:
     returns False if user requested an early termination
      qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
     updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
     clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
     if unknown point, adds a pointer to qh.other_points
       do not deallocate the point's coordinates
 
   notes:
     assumes point is near its best facet and not at a local minimum of a lens
       distributions.  Use qh_findbestfacet to avoid this case.
     uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
 
   see also:
     qh_triangulate() -- triangulate non-simplicial facets
 
   design:
     add point to other_points if needed
     if checkdist
       if point not above facet
         partition coplanar point
         exit
     exit if pre STOPpoint requested
     find horizon and visible facets for point
     make new facets for point to horizon
     make hyperplanes for point
     compute balance statistics
     match neighboring new facets
     update vertex neighbors and delete interior vertices
     exit if STOPcone requested
     merge non-convex new facets
     if merge found, many merges, or 'Qf'
        use qh_findbestnew() instead of qh_findbest()
     partition outside points from visible facets
     delete visible facets
     check polyhedron if requested
     exit if post STOPpoint requested
     reset working lists of facets and vertices
 */
 boolT qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist) {
   int goodvisible, goodhorizon;
   vertexT *vertex;
   facetT *newfacet;
   realT dist, newbalance, pbalance;
   boolT isoutside= False;
   int numpart, numpoints, numnew, firstnew;
 
   qh maxoutdone= False;
   if (qh_pointid(furthest) == -1)
     qh_setappend(&qh other_points, furthest);
   if (!facet) {
     qh_fprintf(qh ferr, 6213, "qhull internal error (qh_addpoint): NULL facet.  Need to call qh_findbestfacet first\n");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   if (checkdist) {
     facet= qh_findbest(furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
                         &dist, &isoutside, &numpart);
     zzadd_(Zpartition, numpart);
     if (!isoutside) {
       zinc_(Znotmax);  /* last point of outsideset is no longer furthest. */
       facet->notfurthest= True;
       qh_partitioncoplanar(furthest, facet, &dist);
       return True;
     }
   }
   qh_buildtracing(furthest, facet);
   if (qh STOPpoint < 0 && qh furthest_id == -qh STOPpoint-1) {
     facet->notfurthest= True;
     return False;
   }
   qh_findhorizon(furthest, facet, &goodvisible, &goodhorizon);
   if (qh ONLYgood && !(goodvisible+goodhorizon) && !qh GOODclosest) {
     zinc_(Znotgood);
     facet->notfurthest= True;
     /* last point of outsideset is no longer furthest.  This is ok
        since all points of the outside are likely to be bad */
     qh_resetlists(False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
     return True;
   }
   zzinc_(Zprocessed);
   firstnew= qh facet_id;
   vertex= qh_makenewfacets(furthest /*visible_list, attaches if !ONLYgood */);
   qh_makenewplanes(/* newfacet_list */);
   numnew= qh facet_id - firstnew;
   newbalance= numnew - (realT) (qh num_facets-qh num_visible)
                          * qh hull_dim/qh num_vertices;
   wadd_(Wnewbalance, newbalance);
   wadd_(Wnewbalance2, newbalance * newbalance);
   if (qh ONLYgood
   && !qh_findgood(qh newfacet_list, goodhorizon) && !qh GOODclosest) {
     FORALLnew_facets
       qh_delfacet(newfacet);
     qh_delvertex(vertex);
     qh_resetlists(True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
     zinc_(Znotgoodnew);
     facet->notfurthest= True;
     return True;
   }
   if (qh ONLYgood)
     qh_attachnewfacets(/*visible_list*/);
   qh_matchnewfacets();
   qh_updatevertices();
   if (qh STOPcone && qh furthest_id == qh STOPcone-1) {
     facet->notfurthest= True;
     return False;  /* visible_list etc. still defined */
   }
   qh findbestnew= False;
   if (qh PREmerge || qh MERGEexact) {
     qh_premerge(vertex, qh premerge_centrum, qh premerge_cos);
     if (qh_USEfindbestnew)
       qh findbestnew= True;
     else {
       FORALLnew_facets {
         if (!newfacet->simplicial) {
           qh findbestnew= True;  /* use qh_findbestnew instead of qh_findbest*/
           break;
         }
       }
     }
   }else if (qh BESToutside)
     qh findbestnew= True;
   qh_partitionvisible(/*qh.visible_list*/ !qh_ALL, &numpoints);
   qh findbestnew= False;
   qh findbest_notsharp= False;
   zinc_(Zpbalance);
   pbalance= numpoints - (realT) qh hull_dim /* assumes all points extreme */
                 * (qh num_points - qh num_vertices)/qh num_vertices;
   wadd_(Wpbalance, pbalance);
   wadd_(Wpbalance2, pbalance * pbalance);
   qh_deletevisible(/*qh.visible_list*/);
   zmax_(Zmaxvertex, qh num_vertices);
   qh NEWfacets= False;
   if (qh IStracing >= 4) {
     if (qh num_facets < 2000)
       qh_printlists();
     qh_printfacetlist(qh newfacet_list, NULL, True);
     qh_checkpolygon(qh facet_list);
   }else if (qh CHECKfrequently) {
     if (qh num_facets < 50)
       qh_checkpolygon(qh facet_list);
     else
       qh_checkpolygon(qh newfacet_list);
   }
   if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1)
     return False;
   qh_resetlists(True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
   /* qh_triangulate(); to test qh.TRInormals */
   trace2((qh ferr, 2056, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",
     qh_pointid(furthest), numnew, newbalance, pbalance));
   return True;
 } /* addpoint */
 
 /*---------------------------------
 
   qh_build_withrestart()
     allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
     qh.FIRSTpoint/qh.NUMpoints is point array
         it may be moved by qh_joggleinput()
 */
 void qh_build_withrestart(void) {
   int restart;
 
   qh ALLOWrestart= True;
   while (True) {
     restart= setjmp(qh restartexit); /* simple statement for CRAY J916 */
     if (restart) {       /* only from qh_precision() */
       zzinc_(Zretry);
       wmax_(Wretrymax, qh JOGGLEmax);
       /* QH7078 warns about using 'TCn' with 'QJn' */
       qh STOPcone= -1; /* if break from joggle, prevents normal output */
     }
     if (!qh RERUN && qh JOGGLEmax < REALmax/2) {
       if (qh build_cnt > qh_JOGGLEmaxretry) {
         qh_fprintf(qh ferr, 6229, "qhull precision error: %d attempts to construct a convex hull\n\
         with joggled input.  Increase joggle above 'QJ%2.2g'\n\
         or modify qh_JOGGLE... parameters in user.h\n",
            qh build_cnt, qh JOGGLEmax);
         qh_errexit(qh_ERRqhull, NULL, NULL);
       }
       if (qh build_cnt && !restart)
         break;
     }else if (qh build_cnt && qh build_cnt >= qh RERUN)
       break;
     qh STOPcone= 0;
     qh_freebuild(True);  /* first call is a nop */
     qh build_cnt++;
     if (!qh qhull_optionsiz)
       qh qhull_optionsiz= (int)strlen(qh qhull_options);   /* WARN64 */
     else {
       qh qhull_options [qh qhull_optionsiz]= '\0';
       qh qhull_optionlen= qh_OPTIONline;  /* starts a new line */
     }
     qh_option("_run", &qh build_cnt, NULL);
     if (qh build_cnt == qh RERUN) {
       qh IStracing= qh TRACElastrun;  /* duplicated from qh_initqhull_globals */
       if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
         qh TRACElevel= (qh IStracing? qh IStracing : 3);
         qh IStracing= 0;
       }
       qhmem.IStracing= qh IStracing;
     }
     if (qh JOGGLEmax < REALmax/2)
       qh_joggleinput();
     qh_initbuild();
     qh_buildhull();
     if (qh JOGGLEmax < REALmax/2 && !qh MERGING)
       qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
   }
   qh ALLOWrestart= False;
 } /* qh_build_withrestart */
 
 /*---------------------------------
 
   qh_buildhull()
     construct a convex hull by adding outside points one at a time
 
   returns:
 
   notes:
     may be called multiple times
     checks facet and vertex lists for incorrect flags
     to recover from STOPcone, call qh_deletevisible and qh_resetlists
 
   design:
     check visible facet and newfacet flags
     check newlist vertex flags and qh.STOPcone/STOPpoint
     for each facet with a furthest outside point
       add point to facet
       exit if qh.STOPcone or qh.STOPpoint requested
     if qh.NARROWhull for initial simplex
       partition remaining outside points to coplanar sets
 */
 void qh_buildhull(void) {
   facetT *facet;
   pointT *furthest;
   vertexT *vertex;
   int id;
 
   trace1((qh ferr, 1037, "qh_buildhull: start build hull\n"));
   FORALLfacets {
     if (facet->visible || facet->newfacet) {
       qh_fprintf(qh ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
                    facet->id);
       qh_errexit(qh_ERRqhull, facet, NULL);
     }
   }
   FORALLvertices {
     if (vertex->newlist) {
       qh_fprintf(qh ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
                    vertex->id);
       qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex);
       qh_errexit(qh_ERRqhull, NULL, NULL);
     }
     id= qh_pointid(vertex->point);
     if ((qh STOPpoint>0 && id == qh STOPpoint-1) ||
         (qh STOPpoint<0 && id == -qh STOPpoint-1) ||
         (qh STOPcone>0 && id == qh STOPcone-1)) {
       trace1((qh ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
       return;
     }
   }
   qh facet_next= qh facet_list;      /* advance facet when processed */
   while ((furthest= qh_nextfurthest(&facet))) {
     qh num_outside--;  /* if ONLYmax, furthest may not be outside */
     if (!qh_addpoint(furthest, facet, qh ONLYmax))
       break;
   }
   if (qh NARROWhull) /* move points from outsideset to coplanarset */
     qh_outcoplanar( /* facet_list */ );
   if (qh num_outside && !furthest) {
     qh_fprintf(qh ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   trace1((qh ferr, 1039, "qh_buildhull: completed the hull construction\n"));
 } /* buildhull */
 
 
 /*---------------------------------
 
   qh_buildtracing( furthest, facet )
     trace an iteration of qh_buildhull() for furthest point and facet
     if !furthest, prints progress message
 
   returns:
     tracks progress with qh.lastreport
     updates qh.furthest_id (-3 if furthest is NULL)
     also resets visit_id, vertext_visit on wrap around
 
   see:
     qh_tracemerging()
 
   design:
     if !furthest
       print progress message
       exit
     if 'TFn' iteration
       print progress message
     else if tracing
       trace furthest point and facet
     reset qh.visit_id and qh.vertex_visit if overflow may occur
     set qh.furthest_id for tracing
 */
 void qh_buildtracing(pointT *furthest, facetT *facet) {
   realT dist= 0;
   float cpu;
   int total, furthestid;
   time_t timedata;
   struct tm *tp;
   vertexT *vertex;
 
   qh old_randomdist= qh RANDOMdist;
   qh RANDOMdist= False;
   if (!furthest) {
     time(&timedata);
     tp= localtime(&timedata);
     cpu= (float)qh_CPUclock - (float)qh hulltime;
     cpu /= (float)qh_SECticks;
     total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
     qh_fprintf(qh ferr, 8118, "\n\
 At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
  The current hull contains %d facets and %d vertices.  Last point was p%d\n",
       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
       total, qh num_facets, qh num_vertices, qh furthest_id);
     return;
   }
   furthestid= qh_pointid(furthest);
   if (qh TRACEpoint == furthestid) {
     qh IStracing= qh TRACElevel;
     qhmem.IStracing= qh TRACElevel;
   }else if (qh TRACEpoint != -1 && qh TRACEdist < REALmax/2) {
     qh IStracing= 0;
     qhmem.IStracing= 0;
   }
   if (qh REPORTfreq && (qh facet_id-1 > qh lastreport+qh REPORTfreq)) {
     qh lastreport= qh facet_id-1;
     time(&timedata);
     tp= localtime(&timedata);
     cpu= (float)qh_CPUclock - (float)qh hulltime;
     cpu /= (float)qh_SECticks;
     total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
     zinc_(Zdistio);
     qh_distplane(furthest, facet, &dist);
     qh_fprintf(qh ferr, 8119, "\n\
 At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
  The current hull contains %d facets and %d vertices.  There are %d\n\
  outside points.  Next is point p%d(v%d), %2.2g above f%d.\n",
       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
       total, qh num_facets, qh num_vertices, qh num_outside+1,
       furthestid, qh vertex_id, dist, getid_(facet));
   }else if (qh IStracing >=1) {
     cpu= (float)qh_CPUclock - (float)qh hulltime;
     cpu /= (float)qh_SECticks;
     qh_distplane(furthest, facet, &dist);
     qh_fprintf(qh ferr, 8120, "qh_addpoint: add p%d(v%d) to hull of %d facets(%2.2g above f%d) and %d outside at %4.4g CPU secs.  Previous was p%d.\n",
       furthestid, qh vertex_id, qh num_facets, dist,
       getid_(facet), qh num_outside+1, cpu, qh furthest_id);
   }
   zmax_(Zvisit2max, (int)qh visit_id/2);
   if (qh visit_id > (unsigned) INT_MAX) {
     zinc_(Zvisit);
     qh visit_id= 0;
     FORALLfacets
       facet->visitid= 0;
   }
   zmax_(Zvvisit2max, (int)qh vertex_visit/2);
   if (qh vertex_visit > (unsigned) INT_MAX/2) { /* 31 bits */
     zinc_(Zvvisit);
     qh vertex_visit= 0;
     FORALLvertices
       vertex->visitid= 0;
   }
   qh furthest_id= furthestid;
   qh RANDOMdist= qh old_randomdist;
 } /* buildtracing */
 
 /*---------------------------------
 
   qh_errexit2( exitcode, facet, otherfacet )
     return exitcode to system after an error
     report two facets
 
   returns:
     assumes exitcode non-zero
 
   see:
     normally use qh_errexit() in user.c(reports a facet and a ridge)
 */
 void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) {
 
   qh_errprint("ERRONEOUS", facet, otherfacet, NULL, NULL);
   qh_errexit(exitcode, NULL, NULL);
 } /* errexit2 */
 
 
 /*---------------------------------
 
   qh_findhorizon( point, facet, goodvisible, goodhorizon )
     given a visible facet, find the point's horizon and visible facets
     for all facets, !facet-visible
 
   returns:
     returns qh.visible_list/num_visible with all visible facets
       marks visible facets with ->visible
     updates count of good visible and good horizon facets
     updates qh.max_outside, qh.max_vertex, facet->maxoutside
 
   see:
     similar to qh_delpoint()
 
   design:
     move facet to qh.visible_list at end of qh.facet_list
     for all visible facets
      for each unvisited neighbor of a visible facet
        compute distance of point to neighbor
        if point above neighbor
          move neighbor to end of qh.visible_list
        else if point is coplanar with neighbor
          update qh.max_outside, qh.max_vertex, neighbor->maxoutside
          mark neighbor coplanar (will create a samecycle later)
          update horizon statistics
 */
 void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
   facetT *neighbor, **neighborp, *visible;
   int numhorizon= 0, coplanar= 0;
   realT dist;
 
   trace1((qh ferr, 1040,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id));
   *goodvisible= *goodhorizon= 0;
   zinc_(Ztotvisible);
   qh_removefacet(facet);  /* visible_list at end of qh facet_list */
   qh_appendfacet(facet);
   qh num_visible= 1;
   if (facet->good)
     (*goodvisible)++;
   qh visible_list= facet;
   facet->visible= True;
   facet->f.replace= NULL;
   if (qh IStracing >=4)
     qh_errprint("visible", facet, NULL, NULL, NULL);
   qh visit_id++;
   FORALLvisible_facets {
     if (visible->tricoplanar && !qh TRInormals) {
       qh_fprintf(qh ferr, 6230, "Qhull internal error (qh_findhorizon): does not work for tricoplanar facets.  Use option 'Q11'\n");
       qh_errexit(qh_ERRqhull, visible, NULL);
     }
     visible->visitid= qh visit_id;
     FOREACHneighbor_(visible) {
       if (neighbor->visitid == qh visit_id)
         continue;
       neighbor->visitid= qh visit_id;
       zzinc_(Znumvisibility);
       qh_distplane(point, neighbor, &dist);
       if (dist > qh MINvisible) {
         zinc_(Ztotvisible);
         qh_removefacet(neighbor);  /* append to end of qh visible_list */
         qh_appendfacet(neighbor);
         neighbor->visible= True;
         neighbor->f.replace= NULL;
         qh num_visible++;
         if (neighbor->good)
           (*goodvisible)++;
         if (qh IStracing >=4)
           qh_errprint("visible", neighbor, NULL, NULL, NULL);
       }else {
         if (dist > - qh MAXcoplanar) {
           neighbor->coplanar= True;
           zzinc_(Zcoplanarhorizon);
           qh_precision("coplanar horizon");
           coplanar++;
           if (qh MERGING) {
             if (dist > 0) {
               maximize_(qh max_outside, dist);
               maximize_(qh max_vertex, dist);
 #if qh_MAXoutside
               maximize_(neighbor->maxoutside, dist);
 #endif
             }else
               minimize_(qh min_vertex, dist);  /* due to merge later */
           }
           trace2((qh ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible(%2.7g)\n",
               qh_pointid(point), neighbor->id, dist, qh MINvisible));
         }else
           neighbor->coplanar= False;
         zinc_(Ztothorizon);
         numhorizon++;
         if (neighbor->good)
           (*goodhorizon)++;
         if (qh IStracing >=4)
           qh_errprint("horizon", neighbor, NULL, NULL, NULL);
       }
     }
   }
   if (!numhorizon) {
     qh_precision("empty horizon");
     qh_fprintf(qh ferr, 6168, "qhull precision error (qh_findhorizon): empty horizon\n\
 QhullPoint p%d was above all facets.\n", qh_pointid(point));
     qh_printfacetlist(qh facet_list, NULL, True);
     qh_errexit(qh_ERRprec, NULL, NULL);
   }
   trace1((qh ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",
        numhorizon, *goodhorizon, qh num_visible, *goodvisible, coplanar));
   if (qh IStracing >= 4 && qh num_facets < 50)
     qh_printlists();
 } /* findhorizon */
 
 /*---------------------------------
 
   qh_nextfurthest( visible )
     returns next furthest point and visible facet for qh_addpoint()
     starts search at qh.facet_next
 
   returns:
     removes furthest point from outside set
     NULL if none available
     advances qh.facet_next over facets with empty outside sets
 
   design:
     for each facet from qh.facet_next
       if empty outside set
         advance qh.facet_next
       else if qh.NARROWhull
         determine furthest outside point
         if furthest point is not outside
           advance qh.facet_next(point will be coplanar)
     remove furthest point from outside set
 */
 pointT *qh_nextfurthest(facetT **visible) {
   facetT *facet;
   int size, idx;
   realT randr, dist;
   pointT *furthest;
 
   while ((facet= qh facet_next) != qh facet_tail) {
     if (!facet->outsideset) {
       qh facet_next= facet->next;
       continue;
     }
     SETreturnsize_(facet->outsideset, size);
     if (!size) {
       qh_setfree(&facet->outsideset);
       qh facet_next= facet->next;
       continue;
     }
     if (qh NARROWhull) {
       if (facet->notfurthest)
         qh_furthestout(facet);
       furthest= (pointT*)qh_setlast(facet->outsideset);
 #if qh_COMPUTEfurthest
       qh_distplane(furthest, facet, &dist);
       zinc_(Zcomputefurthest);
 #else
       dist= facet->furthestdist;
 #endif
       if (dist < qh MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
         qh facet_next= facet->next;
         continue;
       }
     }
     if (!qh RANDOMoutside && !qh VIRTUALmemory) {
       if (qh PICKfurthest) {
         qh_furthestnext(/* qh.facet_list */);
         facet= qh facet_next;
       }
       *visible= facet;
       return((pointT*)qh_setdellast(facet->outsideset));
     }
     if (qh RANDOMoutside) {
       int outcoplanar = 0;
       if (qh NARROWhull) {
         FORALLfacets {
           if (facet == qh facet_next)
             break;
           if (facet->outsideset)
             outcoplanar += qh_setsize( facet->outsideset);
         }
       }
       randr= qh_RANDOMint;
       randr= randr/(qh_RANDOMmax+1);
       idx= (int)floor((qh num_outside - outcoplanar) * randr);
       FORALLfacet_(qh facet_next) {
         if (facet->outsideset) {
           SETreturnsize_(facet->outsideset, size);
           if (!size)
             qh_setfree(&facet->outsideset);
           else if (size > idx) {
             *visible= facet;
             return((pointT*)qh_setdelnth(facet->outsideset, idx));
           }else
             idx -= size;
         }
       }
       qh_fprintf(qh ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
               qh num_outside, idx+1, randr);
       qh_errexit(qh_ERRqhull, NULL, NULL);
     }else { /* VIRTUALmemory */
       facet= qh facet_tail->previous;
       if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {
         if (facet->outsideset)
           qh_setfree(&facet->outsideset);
         qh_removefacet(facet);
         qh_prependfacet(facet, &qh facet_list);
         continue;
       }
       *visible= facet;
       return furthest;
     }
   }
   return NULL;
 } /* nextfurthest */
 
 /*---------------------------------
 
   qh_partitionall( vertices, points, numpoints )
     partitions all points in points/numpoints to the outsidesets of facets
     vertices= vertices in qh.facet_list(!partitioned)
 
   returns:
     builds facet->outsideset
     does not partition qh.GOODpoint
     if qh.ONLYgood && !qh.MERGING,
       does not partition qh.GOODvertex
 
   notes:
     faster if qh.facet_list sorted by anticipated size of outside set
 
   design:
     initialize pointset with all points
     remove vertices from pointset
     remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
     for all facets
       for all remaining points in pointset
         compute distance from point to facet
         if point is outside facet
           remove point from pointset (by not reappending)
           update bestpoint
           append point or old bestpoint to facet's outside set
       append bestpoint to facet's outside set (furthest)
     for all points remaining in pointset
       partition point into facets' outside sets and coplanar sets
 */
 void qh_partitionall(setT *vertices, pointT *points, int numpoints){
   setT *pointset;
   vertexT *vertex, **vertexp;
   pointT *point, **pointp, *bestpoint;
   int size, point_i, point_n, point_end, remaining, i, id;
   facetT *facet;
   realT bestdist= -REALmax, dist, distoutside;
 
   trace1((qh ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));
   pointset= qh_settemp(numpoints);
   qh num_outside= 0;
   pointp= SETaddr_(pointset, pointT);
   for (i=numpoints, point= points; i--; point += qh hull_dim)
     *(pointp++)= point;
   qh_settruncate(pointset, numpoints);
   FOREACHvertex_(vertices) {
     if ((id= qh_pointid(vertex->point)) >= 0)
       SETelem_(pointset, id)= NULL;
   }
   id= qh_pointid(qh GOODpointp);
   if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
     SETelem_(pointset, id)= NULL;
   if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/
     if ((id= qh_pointid(qh GOODvertexp)) >= 0)
       SETelem_(pointset, id)= NULL;
   }
   if (!qh BESToutside) {  /* matches conditional for qh_partitionpoint below */
     distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
     zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */
     remaining= qh num_facets;
     point_end= numpoints;
     FORALLfacets {
       size= point_end/(remaining--) + 100;
       facet->outsideset= qh_setnew(size);
       bestpoint= NULL;
       point_end= 0;
       FOREACHpoint_i_(pointset) {
         if (point) {
           zzinc_(Zpartitionall);
           qh_distplane(point, facet, &dist);
           if (dist < distoutside)
             SETelem_(pointset, point_end++)= point;
           else {
             qh num_outside++;
             if (!bestpoint) {
               bestpoint= point;
               bestdist= dist;
             }else if (dist > bestdist) {
               qh_setappend(&facet->outsideset, bestpoint);
               bestpoint= point;
               bestdist= dist;
             }else
               qh_setappend(&facet->outsideset, point);
           }
         }
       }
       if (bestpoint) {
         qh_setappend(&facet->outsideset, bestpoint);
 #if !qh_COMPUTEfurthest
         facet->furthestdist= bestdist;
 #endif
       }else
         qh_setfree(&facet->outsideset);
       qh_settruncate(pointset, point_end);
     }
   }
   /* if !qh BESToutside, pointset contains points not assigned to outsideset */
   if (qh BESToutside || qh MERGING || qh KEEPcoplanar || qh KEEPinside) {
     qh findbestnew= True;
     FOREACHpoint_i_(pointset) {
       if (point)
         qh_partitionpoint(point, qh facet_list);
     }
     qh findbestnew= False;
   }
   zzadd_(Zpartitionall, zzval_(Zpartition));
   zzval_(Zpartition)= 0;
   qh_settempfree(&pointset);
   if (qh IStracing >= 4)
     qh_printfacetlist(qh facet_list, NULL, True);
 } /* partitionall */
 
 
 /*---------------------------------
 
   qh_partitioncoplanar( point, facet, dist )
     partition coplanar point to a facet
     dist is distance from point to facet
     if dist NULL,
       searches for bestfacet and does nothing if inside
     if qh.findbestnew set,
       searches new facets instead of using qh_findbest()
 
   returns:
     qh.max_ouside updated
     if qh.KEEPcoplanar or qh.KEEPinside
       point assigned to best coplanarset
 
   notes:
     facet->maxoutside is updated at end by qh_check_maxout
 
   design:
     if dist undefined
       find best facet for point
       if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
         exit
     if keeping coplanar/nearinside/inside points
       if point is above furthest coplanar point
         append point to coplanar set (it is the new furthest)
         update qh.max_outside
       else
         append point one before end of coplanar set
     else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
     and bestfacet is more than perpendicular to facet
       repartition the point using qh_findbest() -- it may be put on an outsideset
     else
       update qh.max_outside
 */
 void qh_partitioncoplanar(pointT *point, facetT *facet, realT *dist) {
   facetT *bestfacet;
   pointT *oldfurthest;
   realT bestdist, dist2= 0, angle;
   int numpart= 0, oldfindbest;
   boolT isoutside;
 
   qh WAScoplanar= True;
   if (!dist) {
     if (qh findbestnew)
       bestfacet= qh_findbestnew(point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
     else
       bestfacet= qh_findbest(point, facet, qh_ALL, !qh_ISnewfacets, qh DELAUNAY,
                           &bestdist, &isoutside, &numpart);
     zinc_(Ztotpartcoplanar);
     zzadd_(Zpartcoplanar, numpart);
     if (!qh DELAUNAY && !qh KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
       if (qh KEEPnearinside) {
         if (bestdist < -qh NEARinside) {
           zinc_(Zcoplanarinside);
           trace4((qh ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n",
                   qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
           return;
         }
       }else if (bestdist < -qh MAXcoplanar) {
           trace4((qh ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n",
                   qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
         zinc_(Zcoplanarinside);
         return;
       }
     }
   }else {
     bestfacet= facet;
     bestdist= *dist;
   }
   if (bestdist > qh max_outside) {
     if (!dist && facet != bestfacet) {
       zinc_(Zpartangle);
       angle= qh_getangle(facet->normal, bestfacet->normal);
       if (angle < 0) {
         /* typically due to deleted vertex and coplanar facets, e.g.,
              RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
         zinc_(Zpartflip);
         trace2((qh ferr, 2058, "qh_partitioncoplanar: repartition point p%d from f%d.  It is above flipped facet f%d dist %2.2g\n",
                 qh_pointid(point), facet->id, bestfacet->id, bestdist));
         oldfindbest= qh findbestnew;
         qh findbestnew= False;
         qh_partitionpoint(point, bestfacet);
         qh findbestnew= oldfindbest;
         return;
       }
     }
     qh max_outside= bestdist;
     if (bestdist > qh TRACEdist) {
       qh_fprintf(qh ferr, 8122, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",
                      qh_pointid(point), facet->id, bestdist, bestfacet->id, qh furthest_id);
       qh_errprint("DISTANT", facet, bestfacet, NULL, NULL);
     }
   }
   if (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside) {
     oldfurthest= (pointT*)qh_setlast(bestfacet->coplanarset);
     if (oldfurthest) {
       zinc_(Zcomputefurthest);
       qh_distplane(oldfurthest, bestfacet, &dist2);
     }
     if (!oldfurthest || dist2 < bestdist)
       qh_setappend(&bestfacet->coplanarset, point);
     else
       qh_setappend2ndlast(&bestfacet->coplanarset, point);
   }
   trace4((qh ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d(or inside) dist %2.2g\n",
           qh_pointid(point), bestfacet->id, bestdist));
 } /* partitioncoplanar */
 
 /*---------------------------------
 
   qh_partitionpoint( point, facet )
     assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
     if qh.findbestnew
       uses qh_findbestnew() to search all new facets
     else
       uses qh_findbest()
 
   notes:
     after qh_distplane(), this and qh_findbest() are most expensive in 3-d
 
   design:
     find best facet for point
       (either exhaustive search of new facets or directed search from facet)
     if qh.NARROWhull
       retain coplanar and nearinside points as outside points
     if point is outside bestfacet
       if point above furthest point for bestfacet
         append point to outside set (it becomes the new furthest)
         if outside set was empty
           move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
         update bestfacet->furthestdist
       else
         append point one before end of outside set
     else if point is coplanar to bestfacet
       if keeping coplanar points or need to update qh.max_outside
         partition coplanar point into bestfacet
     else if near-inside point
       partition as coplanar point into bestfacet
     else is an inside point
       if keeping inside points
         partition as coplanar point into bestfacet
 */
 void qh_partitionpoint(pointT *point, facetT *facet) {
   realT bestdist;
   boolT isoutside;
   facetT *bestfacet;
   int numpart;
 #if qh_COMPUTEfurthest
   realT dist;
 #endif
 
   if (qh findbestnew)
     bestfacet= qh_findbestnew(point, facet, &bestdist, qh BESToutside, &isoutside, &numpart);
   else
     bestfacet= qh_findbest(point, facet, qh BESToutside, qh_ISnewfacets, !qh_NOupper,
                           &bestdist, &isoutside, &numpart);
   zinc_(Ztotpartition);
   zzadd_(Zpartition, numpart);
   if (qh NARROWhull) {
     if (qh DELAUNAY && !isoutside && bestdist >= -qh MAXcoplanar)
       qh_precision("nearly incident point(narrow hull)");
     if (qh KEEPnearinside) {
       if (bestdist >= -qh NEARinside)
         isoutside= True;
     }else if (bestdist >= -qh MAXcoplanar)
       isoutside= True;
   }
 
   if (isoutside) {
     if (!bestfacet->outsideset
     || !qh_setlast(bestfacet->outsideset)) {
       qh_setappend(&(bestfacet->outsideset), point);
       if (!bestfacet->newfacet) {
         qh_removefacet(bestfacet);  /* make sure it's after qh facet_next */
         qh_appendfacet(bestfacet);
       }
 #if !qh_COMPUTEfurthest
       bestfacet->furthestdist= bestdist;
 #endif
     }else {
 #if qh_COMPUTEfurthest
       zinc_(Zcomputefurthest);
       qh_distplane(oldfurthest, bestfacet, &dist);
       if (dist < bestdist)
         qh_setappend(&(bestfacet->outsideset), point);
       else
         qh_setappend2ndlast(&(bestfacet->outsideset), point);
 #else
       if (bestfacet->furthestdist < bestdist) {
         qh_setappend(&(bestfacet->outsideset), point);
         bestfacet->furthestdist= bestdist;
       }else
         qh_setappend2ndlast(&(bestfacet->outsideset), point);
 #endif
     }
     qh num_outside++;
     trace4((qh ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d new? %d (or narrowhull)\n",
           qh_pointid(point), bestfacet->id, bestfacet->newfacet));
   }else if (qh DELAUNAY || bestdist >= -qh MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
     zzinc_(Zcoplanarpart);
     if (qh DELAUNAY)
       qh_precision("nearly incident point");
     if ((qh KEEPcoplanar + qh KEEPnearinside) || bestdist > qh max_outside)
       qh_partitioncoplanar(point, bestfacet, &bestdist);
     else {
       trace4((qh ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
           qh_pointid(point), bestfacet->id));
     }
   }else if (qh KEEPnearinside && bestdist > -qh NEARinside) {
     zinc_(Zpartnear);
     qh_partitioncoplanar(point, bestfacet, &bestdist);
   }else {
     zinc_(Zpartinside);
     trace4((qh ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
           qh_pointid(point), bestfacet->id, bestdist));
     if (qh KEEPinside)
       qh_partitioncoplanar(point, bestfacet, &bestdist);
   }
 } /* partitionpoint */
 
 /*---------------------------------
 
   qh_partitionvisible( allpoints, numoutside )
     partitions points in visible facets to qh.newfacet_list
     qh.visible_list= visible facets
     for visible facets
       1st neighbor (if any) points to a horizon facet or a new facet
     if allpoints(!used),
       repartitions coplanar points
 
   returns:
     updates outside sets and coplanar sets of qh.newfacet_list
     updates qh.num_outside (count of outside points)
 
   notes:
     qh.findbest_notsharp should be clear (extra work if set)
 
   design:
     for all visible facets with outside set or coplanar set
       select a newfacet for visible facet
       if outside set
         partition outside set into new facets
       if coplanar set and keeping coplanar/near-inside/inside points
         if allpoints
           partition coplanar set into new facets, may be assigned outside
         else
           partition coplanar set into coplanar sets of new facets
     for each deleted vertex
       if allpoints
         partition vertex into new facets, may be assigned outside
       else
         partition vertex into coplanar sets of new facets
 */
 void qh_partitionvisible(/*qh.visible_list*/ boolT allpoints, int *numoutside) {
   facetT *visible, *newfacet;
   pointT *point, **pointp;
   int coplanar=0, size;
   unsigned count;
   vertexT *vertex, **vertexp;
 
   if (qh ONLYmax)
     maximize_(qh MINoutside, qh max_vertex);
   *numoutside= 0;
   FORALLvisible_facets {
     if (!visible->outsideset && !visible->coplanarset)
       continue;
     newfacet= visible->f.replace;
     count= 0;
     while (newfacet && newfacet->visible) {
       newfacet= newfacet->f.replace;
       if (count++ > qh facet_id)
         qh_infiniteloop(visible);
     }
     if (!newfacet)
       newfacet= qh newfacet_list;
     if (newfacet == qh facet_tail) {
       qh_fprintf(qh ferr, 6170, "qhull precision error (qh_partitionvisible): all new facets deleted as\n        degenerate facets. Can not continue.\n");
       qh_errexit(qh_ERRprec, NULL, NULL);
     }
     if (visible->outsideset) {
       size= qh_setsize(visible->outsideset);
       *numoutside += size;
       qh num_outside -= size;
       FOREACHpoint_(visible->outsideset)
         qh_partitionpoint(point, newfacet);
     }
     if (visible->coplanarset && (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside)) {
       size= qh_setsize(visible->coplanarset);
       coplanar += size;
       FOREACHpoint_(visible->coplanarset) {
         if (allpoints) /* not used */
           qh_partitionpoint(point, newfacet);
         else
           qh_partitioncoplanar(point, newfacet, NULL);
       }
     }
   }
   FOREACHvertex_(qh del_vertices) {
     if (vertex->point) {
       if (allpoints) /* not used */
         qh_partitionpoint(vertex->point, qh newfacet_list);
       else
         qh_partitioncoplanar(vertex->point, qh newfacet_list, NULL);
     }
   }
   trace1((qh ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
 } /* partitionvisible */
 
 
 
 /*---------------------------------
 
   qh_precision( reason )
     restart on precision errors if not merging and if 'QJn'
 */
 void qh_precision(const char *reason) {
 
   if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) {
     if (qh JOGGLEmax < REALmax/2) {
       trace0((qh ferr, 26, "qh_precision: qhull restart because of %s\n", reason));
       longjmp(qh restartexit, qh_ERRprec);
     }
   }
 } /* qh_precision */
 
 /*---------------------------------
 
   qh_printsummary( fp )
     prints summary to fp
 
   notes:
     not in io.c so that user_eg.c can prevent io.c from loading
     qh_printsummary and qh_countfacets must match counts
 
   design:
     determine number of points, vertices, and coplanar points
     print summary
 */
 void qh_printsummary(FILE *fp) {
   realT ratio, outerplane, innerplane;
   float cpu;
   int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;
   int goodused;
   facetT *facet;
   const char *s;
   int numdel= zzval_(Zdelvertextot);
   int numtricoplanars= 0;
 
   size= qh num_points + qh_setsize(qh other_points);
   numvertices= qh num_vertices - qh_setsize(qh del_vertices);
   id= qh_pointid(qh GOODpointp);
   FORALLfacets {
     if (facet->coplanarset)
       numcoplanars += qh_setsize( facet->coplanarset);
     if (facet->good) {
       if (facet->simplicial) {
         if (facet->keepcentrum && facet->tricoplanar)
           numtricoplanars++;
       }else if (qh_setsize(facet->vertices) != qh hull_dim)
         nonsimplicial++;
     }
   }
   if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
     size--;
   if (qh STOPcone || qh STOPpoint)
       qh_fprintf(fp, 9288, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");
   if (qh UPPERdelaunay)
     goodused= qh GOODvertex + qh GOODpoint + qh SPLITthresholds;
   else if (qh DELAUNAY)
     goodused= qh GOODvertex + qh GOODpoint + qh GOODthreshold;
   else
     goodused= qh num_good;
   nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
   if (qh VORONOI) {
     if (qh UPPERdelaunay)
       qh_fprintf(fp, 9289, "\n\
 Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
     else
       qh_fprintf(fp, 9290, "\n\
 Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
     qh_fprintf(fp, 9291, "  Number of Voronoi regions%s: %d\n",
               qh ATinfinity ? " and at-infinity" : "", numvertices);
     if (numdel)
       qh_fprintf(fp, 9292, "  Total number of deleted points due to merging: %d\n", numdel);
     if (numcoplanars - numdel > 0)
       qh_fprintf(fp, 9293, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
     else if (size - numvertices - numdel > 0)
       qh_fprintf(fp, 9294, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
     qh_fprintf(fp, 9295, "  Number of%s Voronoi vertices: %d\n",
               goodused ? " 'good'" : "", qh num_good);
     if (nonsimplicial)
       qh_fprintf(fp, 9296, "  Number of%s non-simplicial Voronoi vertices: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }else if (qh DELAUNAY) {
     if (qh UPPERdelaunay)
       qh_fprintf(fp, 9297, "\n\
 Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
     else
       qh_fprintf(fp, 9298, "\n\
 Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
     qh_fprintf(fp, 9299, "  Number of input sites%s: %d\n",
               qh ATinfinity ? " and at-infinity" : "", numvertices);
     if (numdel)
       qh_fprintf(fp, 9300, "  Total number of deleted points due to merging: %d\n", numdel);
     if (numcoplanars - numdel > 0)
       qh_fprintf(fp, 9301, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
     else if (size - numvertices - numdel > 0)
       qh_fprintf(fp, 9302, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
     qh_fprintf(fp, 9303, "  Number of%s Delaunay regions: %d\n",
               goodused ? " 'good'" : "", qh num_good);
     if (nonsimplicial)
       qh_fprintf(fp, 9304, "  Number of%s non-simplicial Delaunay regions: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }else if (qh HALFspace) {
     qh_fprintf(fp, 9305, "\n\
 Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
     qh_fprintf(fp, 9306, "  Number of halfspaces: %d\n", size);
     qh_fprintf(fp, 9307, "  Number of non-redundant halfspaces: %d\n", numvertices);
     if (numcoplanars) {
       if (qh KEEPinside && qh KEEPcoplanar)
         s= "similar and redundant";
       else if (qh KEEPinside)
         s= "redundant";
       else
         s= "similar";
       qh_fprintf(fp, 9308, "  Number of %s halfspaces: %d\n", s, numcoplanars);
     }
     qh_fprintf(fp, 9309, "  Number of intersection points: %d\n", qh num_facets - qh num_visible);
     if (goodused)
       qh_fprintf(fp, 9310, "  Number of 'good' intersection points: %d\n", qh num_good);
     if (nonsimplicial)
       qh_fprintf(fp, 9311, "  Number of%s non-simplicial intersection points: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }else {
     qh_fprintf(fp, 9312, "\n\
 Convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
     qh_fprintf(fp, 9313, "  Number of vertices: %d\n", numvertices);
     if (numcoplanars) {
       if (qh KEEPinside && qh KEEPcoplanar)
         s= "coplanar and interior";
       else if (qh KEEPinside)
         s= "interior";
       else
         s= "coplanar";
       qh_fprintf(fp, 9314, "  Number of %s points: %d\n", s, numcoplanars);
     }
     qh_fprintf(fp, 9315, "  Number of facets: %d\n", qh num_facets - qh num_visible);
     if (goodused)
       qh_fprintf(fp, 9316, "  Number of 'good' facets: %d\n", qh num_good);
     if (nonsimplicial)
       qh_fprintf(fp, 9317, "  Number of%s non-simplicial facets: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }
   if (numtricoplanars)
       qh_fprintf(fp, 9318, "  Number of triangulated facets: %d\n", numtricoplanars);
   qh_fprintf(fp, 9319, "\nStatistics for: %s | %s",
                       qh rbox_command, qh qhull_command);
   if (qh ROTATErandom != INT_MIN)
     qh_fprintf(fp, 9320, " QR%d\n\n", qh ROTATErandom);
   else
     qh_fprintf(fp, 9321, "\n\n");
   qh_fprintf(fp, 9322, "  Number of points processed: %d\n", zzval_(Zprocessed));
   qh_fprintf(fp, 9323, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
   if (qh DELAUNAY)
     qh_fprintf(fp, 9324, "  Number of facets in hull: %d\n", qh num_facets - qh num_visible);
   qh_fprintf(fp, 9325, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
       zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
 #if 0  /* NOTE: must print before printstatistics() */
   {realT stddev, ave;
   qh_fprintf(fp, 9326, "  average new facet balance: %2.2g\n",
           wval_(Wnewbalance)/zval_(Zprocessed));
   stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                  wval_(Wnewbalance2), &ave);
   qh_fprintf(fp, 9327, "  new facet standard deviation: %2.2g\n", stddev);
   qh_fprintf(fp, 9328, "  average partition balance: %2.2g\n",
           wval_(Wpbalance)/zval_(Zpbalance));
   stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                  wval_(Wpbalance2), &ave);
   qh_fprintf(fp, 9329, "  partition standard deviation: %2.2g\n", stddev);
   }
 #endif
   if (nummerged) {
     qh_fprintf(fp, 9330,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
           zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+
           zzval_(Zdistzero));
     qh_fprintf(fp, 9331,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart));
     qh_fprintf(fp, 9332,"  Number of merged facets: %d\n", nummerged);
   }
   if (!qh RANDOMoutside && qh QHULLfinished) {
     cpu= (float)qh hulltime;
     cpu /= (float)qh_SECticks;
     wval_(Wcpu)= cpu;
     qh_fprintf(fp, 9333, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
   }
   if (qh RERUN) {
     if (!qh PREmerge && !qh MERGEexact)
       qh_fprintf(fp, 9334, "  Percentage of runs with precision errors: %4.1f\n",
            zzval_(Zretry)*100.0/qh build_cnt);  /* careful of order */
   }else if (qh JOGGLEmax < REALmax/2) {
     if (zzval_(Zretry))
       qh_fprintf(fp, 9335, "  After %d retries, input joggled by: %2.2g\n",
          zzval_(Zretry), qh JOGGLEmax);
     else
       qh_fprintf(fp, 9336, "  Input joggled by: %2.2g\n", qh JOGGLEmax);
   }
   if (qh totarea != 0.0)
     qh_fprintf(fp, 9337, "  %s facet area:   %2.8g\n",
             zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea);
   if (qh totvol != 0.0)
     qh_fprintf(fp, 9338, "  %s volume:       %2.8g\n",
             zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol);
   if (qh MERGING) {
     qh_outerinner(NULL, &outerplane, &innerplane);
     if (outerplane > 2 * qh DISTround) {
       qh_fprintf(fp, 9339, "  Maximum distance of %spoint above facet: %2.2g",
             (qh QHULLfinished ? "" : "merged "), outerplane);
       ratio= outerplane/(qh ONEmerge + qh DISTround);
       /* don't report ratio if MINoutside is large */
       if (ratio > 0.05 && 2* qh ONEmerge > qh MINoutside && qh JOGGLEmax > REALmax/2)
         qh_fprintf(fp, 9340, " (%.1fx)\n", ratio);
       else
         qh_fprintf(fp, 9341, "\n");
     }
     if (innerplane < -2 * qh DISTround) {
       qh_fprintf(fp, 9342, "  Maximum distance of %svertex below facet: %2.2g",
             (qh QHULLfinished ? "" : "merged "), innerplane);
       ratio= -innerplane/(qh ONEmerge+qh DISTround);
       if (ratio > 0.05 && qh JOGGLEmax > REALmax/2)
         qh_fprintf(fp, 9343, " (%.1fx)\n", ratio);
       else
         qh_fprintf(fp, 9344, "\n");
     }
   }
   qh_fprintf(fp, 9345, "\n");
 } /* printsummary */
 
 
diff --git a/src/libqhull/libqhull.h b/src/libqhull/libqhull.h
index 6762352..aa6f91b 100644
--- a/src/libqhull/libqhull.h
+++ b/src/libqhull/libqhull.h
@@ -1,1101 +1,1101 @@
 /*
  ---------------------------------
 
    libqhull.h
    user-level header file for using qhull.a library
 
    see qh-qhull.htm, qhull_a.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/libqhull.h#10 $$Change: 1708 $
-   $DateTime: 2014/03/26 19:13:56 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/libqhull.h#11 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    NOTE: access to qh_qh is via the 'qh' macro.  This allows
    qh_qh to be either a pointer or a structure.  An example
    of using qh is "qh.DROPdim" which accesses the DROPdim
    field of qh_qh.  Similarly, access to qh_qhstat is via
    the 'qhstat' macro.
 
    includes function prototypes for libqhull.c, geom.c, global.c, io.c, user.c
 
    use mem.h for mem.c
    use qset.h for qset.c
 
    see unix.c for an example of using libqhull.h
 
    recompile qhull if you change this file
 */
 
 #ifndef qhDEFlibqhull
 #define qhDEFlibqhull 1
 
 /*=========================== -included files ==============*/
 
 #include "user.h"      /* user definable constants (e.g., qh_QHpointer) */
 
 #include 
 #include 
 #include 
 #include 
 
 #if __MWERKS__ && __POWERPC__
 #include  
 #include  
 #include        
 #endif
 
 #ifndef __STDC__
 #ifndef __cplusplus
 #if     !_MSC_VER
 #error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
 #error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
 #error  your compiler is a standard C compiler, you can delete this warning from libqhull.h
 #endif
 #endif
 #endif
 
 /*============ constants and basic types ====================*/
 
 extern const char *qh_version; /* defined in global.c */
 
 /*----------------------------------
 
   coordT
     coordinates and coefficients are stored as realT (i.e., double)
 
   notes:
     Qhull works well if realT is 'float'.  If so joggle (QJ) is not effective.
 
     Could use 'float' for data and 'double' for calculations (realT vs. coordT)
       This requires many type casts, and adjusted error bounds.
       Also C compilers may do expressions in double anyway.
 */
 #define coordT realT
 
 /*----------------------------------
 
   pointT
     a point is an array of coordinates, usually qh.hull_dim
 */
 #define pointT coordT
 
 /*----------------------------------
 
   flagT
     Boolean flag as a bit
 */
 #define flagT unsigned int
 
 /*----------------------------------
 
   boolT
     boolean value, either True or False
 
   notes:
     needed for portability
     Use qh_False/qh_True as synonyms
 */
 #define boolT unsigned int
 #ifdef False
 #undef False
 #endif
 #ifdef True
 #undef True
 #endif
 #define False 0
 #define True 1
 #define qh_False 0
 #define qh_True 1
 
 /*----------------------------------
 
   qh_CENTER
     to distinguish facet->center
 */
 typedef enum
 {
     qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
 }
 qh_CENTER;
 
 /*----------------------------------
 
   qh_PRINT
     output formats for printing (qh.PRINTout).
     'Fa' 'FV' 'Fc' 'FC'
 
 
    notes:
    some of these names are similar to qhT names.  The similar names are only
    used in switch statements in qh_printbegin() etc.
 */
 typedef enum {qh_PRINTnone= 0,
   qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
   qh_PRINTcoplanars, qh_PRINTcentrums,
   qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
   qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors,
   qh_PRINTnormals, qh_PRINTouter, qh_PRINTmaple, /* 'n' 'Fo' 'i' 'm' 'Fm' 'FM', 'o' */
   qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff,
   qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
   qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize,
   qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
   qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
   qh_PRINTEND} qh_PRINT;
 
 /*----------------------------------
 
   qh_ALL
     argument flag for selecting everything
 */
 #define qh_ALL      True
 #define qh_NOupper  True     /* argument for qh_findbest */
 #define qh_IScheckmax  True     /* argument for qh_findbesthorizon */
 #define qh_ISnewfacets  True     /* argument for qh_findbest */
 #define qh_RESETvisible  True     /* argument for qh_resetlists */
 
 /*----------------------------------
 
   qh_ERR
     Qhull exit codes, for indicating errors
     See: MSG_ERROR and MSG_WARNING [user.h]
 */
 #define qh_ERRnone  0    /* no error occurred during qhull */
 #define qh_ERRinput 1    /* input inconsistency */
 #define qh_ERRsingular 2 /* singular input data */
 #define qh_ERRprec  3    /* precision error */
 #define qh_ERRmem   4    /* insufficient memory, matches mem.h */
 #define qh_ERRqhull 5    /* internal error detected, matches mem.h */
 
 /*----------------------------------
 
 qh_FILEstderr
 Fake stderr to distinguish error output from normal output
 For C++ interface.  Must redefine qh_fprintf_qhull
 */
 #define qh_FILEstderr ((FILE*)1)
 
 /* ============ -structures- ====================
    each of the following structures is defined by a typedef
    all realT and coordT fields occur at the beginning of a structure
         (otherwise space may be wasted due to alignment)
    define all flags together and pack into 32-bit number
 */
 
 typedef struct vertexT vertexT;
 typedef struct ridgeT ridgeT;
 typedef struct facetT facetT;
 #ifndef DEFsetT
 #define DEFsetT 1
 typedef struct setT setT;          /* defined in qset.h */
 #endif
 
 #ifndef DEFqhstatT
 #define DEFqhstatT 1
 typedef struct qhstatT qhstatT;    /* defined in stat.h */
 #endif
 
 /*----------------------------------
 
   facetT
     defines a facet
 
   notes:
    qhull() generates the hull as a list of facets.
 
   topological information:
     f.previous,next     doubly-linked list of facets
     f.vertices          set of vertices
     f.ridges            set of ridges
     f.neighbors         set of neighbors
     f.toporient         True if facet has top-orientation (else bottom)
 
   geometric information:
     f.offset,normal     hyperplane equation
     f.maxoutside        offset to outer plane -- all points inside
     f.center            centrum for testing convexity
     f.simplicial        True if facet is simplicial
     f.flipped           True if facet does not include qh.interior_point
 
   for constructing hull:
     f.visible           True if facet on list of visible facets (will be deleted)
     f.newfacet          True if facet on list of newly created facets
     f.coplanarset       set of points coplanar with this facet
                         (includes near-inside points for later testing)
     f.outsideset        set of points outside of this facet
     f.furthestdist      distance to furthest point of outside set
     f.visitid           marks visited facets during a loop
     f.replace           replacement facet for to-be-deleted, visible facets
     f.samecycle,newcycle cycle of facets for merging into horizon facet
 
   see below for other flags and fields
 */
 struct facetT {
 #if !qh_COMPUTEfurthest
   coordT   furthestdist;/* distance to furthest point of outsideset */
 #endif
 #if qh_MAXoutside
   coordT   maxoutside;  /* max computed distance of point to facet
                         Before QHULLfinished this is an approximation
                         since maxdist not always set for mergefacet
                         Actual outer plane is +DISTround and
                         computed outer plane is +2*DISTround */
 #endif
   coordT   offset;      /* exact offset of hyperplane from origin */
   coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
                         /*   if tricoplanar, shared with a neighbor */
   union {               /* in order of testing */
    realT   area;        /* area of facet, only in io.c if  ->isarea */
    facetT *replace;     /*  replacement facet if ->visible and NEWfacets
                              is NULL only if qh_mergedegen_redundant or interior */
    facetT *samecycle;   /*  cycle of facets from the same visible/horizon intersection,
                              if ->newfacet */
    facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */
    facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
    facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
   }f;
   coordT  *center;      /*  centrum for convexity, qh.CENTERtype == qh_AScentrum */
                         /*  Voronoi center, qh.CENTERtype == qh_ASvoronoi */
                         /*   if tricoplanar, shared with a neighbor */
   facetT  *previous;    /* previous facet in the facet_list */
   facetT  *next;        /* next facet in the facet_list */
   setT    *vertices;    /* vertices for this facet, inverse sorted by ID
                            if simplicial, 1st vertex was apex/furthest */
   setT    *ridges;      /* explicit ridges for nonsimplicial facets.
                            for simplicial facets, neighbors define the ridges */
   setT    *neighbors;   /* neighbors of the facet.  If simplicial, the kth
                            neighbor is opposite the kth vertex, and the first
                            neighbor is the horizon facet for the first vertex*/
   setT    *outsideset;  /* set of points outside this facet
                            if non-empty, last point is furthest
                            if NARROWhull, includes coplanars for partitioning*/
   setT    *coplanarset; /* set of points coplanar with this facet
                            > qh.min_vertex and <= facet->max_outside
                            a point is assigned to the furthest facet
                            if non-empty, last point is furthest away */
   unsigned visitid;     /* visit_id, for visiting all neighbors,
                            all uses are independent */
   unsigned id;          /* unique identifier from qh.facet_id */
   unsigned nummerge:9;  /* number of merges */
 #define qh_MAXnummerge 511 /*     2^9-1, 32 flags total, see "flags:" in io.c */
   flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
                           /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
                           /*   all tricoplanars share the same apex */
                           /*   if ->degenerate, does not span facet (one logical ridge) */
                           /*   one tricoplanar has ->keepcentrum and ->coplanarset */
                           /*   during qh_triangulate, f.trivisible points to original facet */
   flagT    newfacet:1;  /* True if facet on qh.newfacet_list (new or merged) */
   flagT    visible:1;   /* True if visible facet (will be deleted) */
   flagT    toporient:1; /* True if created with top orientation
                            after merging, use ridge orientation */
   flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
   flagT    seen:1;      /* used to perform operations only once, like visitid */
   flagT    seen2:1;     /* used to perform operations only once, like visitid */
   flagT    flipped:1;   /* True if facet is flipped */
   flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
   flagT    notfurthest:1; /* True if last point of outsideset is not furthest*/
 
 /*-------- flags primarily for output ---------*/
   flagT    good:1;      /* True if a facet marked good for output */
   flagT    isarea:1;    /* True if facet->f.area is defined */
 
 /*-------- flags for merging ------------------*/
   flagT    dupridge:1;  /* True if duplicate ridge in facet */
   flagT    mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge
                             ->normal defined (also defined for mergeridge2) */
   flagT    mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (mark_dupridges */
   flagT    coplanar:1;  /* True if horizon facet is coplanar at last use */
   flagT     mergehorizon:1; /* True if will merge into horizon (->coplanar) */
   flagT     cycledone:1;/* True if mergecycle_all already done */
   flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
   flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */
   flagT    newmerge:1;  /* True if facet is newly merged for reducevertices */
   flagT    degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
   flagT    redundant:1;  /* True if facet is redundant (degen_mergeset) */
 };
 
 
 /*----------------------------------
 
   ridgeT
     defines a ridge
 
   notes:
   a ridge is hull_dim-1 simplex between two neighboring facets.  If the
   facets are non-simplicial, there may be more than one ridge between
   two facets.  E.G. a 4-d hypercube has two triangles between each pair
   of neighboring facets.
 
   topological information:
     vertices            a set of vertices
     top,bottom          neighboring facets with orientation
 
   geometric information:
     tested              True if ridge is clearly convex
     nonconvex           True if ridge is non-convex
 */
 struct ridgeT {
   setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID
                            NULL if a degen ridge (matchsame) */
   facetT  *top;         /* top facet this ridge is part of */
   facetT  *bottom;      /* bottom facet this ridge is part of */
   unsigned id:24;       /* unique identifier, =>room for 8 flags, bit field matches qh.ridge_id */
   flagT    seen:1;      /* used to perform operations only once */
   flagT    tested:1;    /* True when ridge is tested for convexity */
   flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
                            only one ridge between neighbors may have nonconvex */
 };
 
 /*----------------------------------
 
   vertexT
      defines a vertex
 
   topological information:
     next,previous       doubly-linked list of all vertices
     neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
 
   geometric information:
     point               array of DIM3 coordinates
 */
 struct vertexT {
   vertexT *next;        /* next vertex in vertex_list */
   vertexT *previous;    /* previous vertex in vertex_list */
   pointT  *point;       /* hull_dim coordinates (coordT) */
   setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
                            inits in io.c or after first merge */
   unsigned visitid:31;  /* for use with qh.vertex_visit, size must match */
   flagT    seen2:1;     /* another seen flag */
   unsigned id:24;       /* unique identifier, bit field matches qh.vertex_id */
   unsigned dim:4;       /* dimension of point if non-zero, used by cpp */
                         /* =>room for 4 flags */
   flagT    seen:1;      /* used to perform operations only once */
   flagT    delridge:1;  /* vertex was part of a deleted ridge */
   flagT    deleted:1;   /* true if vertex on qh.del_vertices */
   flagT    newlist:1;   /* true if vertex on qh.newvertex_list */
 };
 
 #define MAX_vdim 15  /* Maximum size of vertex->dim */
 
 /*======= -global variables -qh ============================*/
 
 /*----------------------------------
 
   qh
    all global variables for qhull are in qh, qhmem, and qhstat
 
   notes:
    qhmem is defined in mem.h, qhstat is defined in stat.h, qhrbox is defined in rboxpoints.h
    Access to qh_qh is via the "qh" macro.  See qh_QHpointer in user.h
 
    All global variables for qhull are in qh, qhmem, and qhstat
    qh must be unique for each instance of qhull
    qhstat may be shared between qhull instances.
    qhmem may be shared across multiple instances of Qhull.
    Rbox uses global variables rbox_inuse and rbox, but does not persist data across calls.
 
    Qhull is not multithreaded.  Global state could be stored in thread-local storage.
 */
 
 extern int qhull_inuse;
 
 typedef struct qhT qhT;
 #if qh_QHpointer_dllimport
 #define qh qh_qh->
 __declspec(dllimport) extern qhT *qh_qh;     /* allocated in global.c */
 #elif qh_QHpointer
 #define qh qh_qh->
 extern qhT *qh_qh;     /* allocated in global.c */
 #elif qh_dllimport
 #define qh qh_qh.
 __declspec(dllimport) extern qhT qh_qh;      /* allocated in global.c */
 #else
 #define qh qh_qh.
 extern qhT qh_qh;
 #endif
 
 struct qhT {
 
 /*----------------------------------
 
   qh constants
     configuration flags and constants for Qhull
 
   notes:
     The user configures Qhull by defining flags.  They are
     copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
 */
   boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
   boolT ANGLEmerge;       /* true 'Qa' if sort potential merges by angle */
   boolT APPROXhull;       /* true 'Wn' if MINoutside set */
   realT   MINoutside;     /*   'Wn' min. distance for an outside point */
   boolT ANNOTATEoutput;   /* true 'Ta' if annotate output with message codes */
   boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
                              for improving precision in Delaunay triangulations */
   boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
   boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
   boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
   boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
   boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
   realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
   realT postmerge_cos;    /*   'An'    cos_max when post merging */
   boolT DELAUNAY;         /* true 'd' if computing DELAUNAY triangulation */
   boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
   int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
   boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
   int   GOODpoint;        /* 1+n for 'QGn', good facet if visible/not(-) from point n*/
   pointT *GOODpointp;     /*   the actual point */
   boolT GOODthreshold;    /* true if qh.lower_threshold/upper_threshold defined
                              false if qh.SPLITthreshold */
   int   GOODvertex;       /* 1+n, good facet if vertex for point n */
   pointT *GOODvertexp;     /*   the actual point */
   boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
   boolT ISqhullQh;        /* Set by Qhull.cpp on initialization */
   int   IStracing;        /* trace execution, 0=none, 1=least, 4=most, -1=events */
   int   KEEParea;         /* 'PAn' number of largest facets to keep */
   boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
   boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
                               set automatically if 'd Qc' */
   int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
   realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
   realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
   boolT MERGEexact;       /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */
   boolT MERGEindependent; /* true 'Q2' if merging independent sets */
   boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
   realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
   realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
   boolT MERGEvertices;    /* true 'Q3' if merging redundant vertices */
   realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
   boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
   boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning */
   boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
   boolT ONLYgood;         /* true 'Qg' if process points with good visible or horizon facets */
   boolT ONLYmax;          /* true 'Qm' if only process points that increase max_outside */
   boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
   boolT POSTmerge;        /* true if merging after buildhull (Cn or An) */
   boolT PREmerge;         /* true if merging during buildhull (C-n or A-n) */
                         /* NOTE: some of these names are similar to qh_PRINT names */
   boolT PRINTcentrums;    /* true 'Gc' if printing centrums */
   boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
   int   PRINTdim;         /* print dimension for Geomview output */
   boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
   boolT PRINTgood;        /* true 'Pg' if printing good facets */
   boolT PRINTinner;       /* true 'Gi' if printing inner planes */
   boolT PRINTneighbors;   /* true 'PG' if printing neighbors of good facets */
   boolT PRINTnoplanes;    /* true 'Gn' if printing no planes */
   boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
   boolT PRINTouter;       /* true 'Go' if printing outer planes */
   boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
   qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
   boolT PRINTridges;      /* true 'Gr' if print ridges */
   boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
   boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
   boolT PRINTsummary;     /* true 's' if printing summary to stderr */
   boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
   boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
                              need projectinput() for Delaunay in qh_init_B */
   int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
   boolT QUICKhelp;        /* true if quick help message for degen input */
   boolT RANDOMdist;       /* true if randomly change distplane and setfacetplane */
   realT RANDOMfactor;     /*    maximum random perturbation */
   realT RANDOMa;          /*    qh_randomfactor is randr * RANDOMa + RANDOMb */
   realT RANDOMb;
   boolT RANDOMoutside;    /* true if select a random outside point */
   int   REPORTfreq;       /* buildtracing reports every n facets */
   int   REPORTfreq2;      /* tracemerging reports every REPORTfreq/2 facets */
   int   RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
   int   ROTATErandom;     /* 'QRn' seed, 0 time, >= rotate input */
   boolT SCALEinput;       /* true 'Qbk' if scaling input */
   boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
   boolT SETroundoff;      /* true 'E' if qh.DISTround is predefined */
   boolT SKIPcheckmax;     /* true 'Q5' if skip qh_check_maxout */
   boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
   boolT SPLITthresholds;  /* true if upper_/lower_threshold defines a region
                                used only for printing (!for qh.ONLYgood) */
   int   STOPcone;         /* 'TCn' 1+n for stopping after cone for point n */
                           /*       also used by qh_build_withresart for err exit*/
   int   STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
                                         adding point n */
   int   TESTpoints;       /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
   boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
   int   TRACElevel;       /* 'Tn' conditional IStracing level */
   int   TRACElastrun;     /*  qh.TRACElevel applies to last qh.RERUN */
   int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex */
   realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
   int   TRACEmerge;       /* 'TMn' start tracing before this merge */
   boolT TRIangulate;      /* true 'Qt' if triangulate non-simplicial facets */
   boolT TRInormals;       /* true 'Q11' if triangulate duplicates normals (sets Qt) */
   boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
   boolT USEstdout;        /* true 'Tz' if using stdout instead of stderr */
   boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
   boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
   boolT VORONOI;          /* true 'v' if computing Voronoi diagram */
 
   /*--------input constants ---------*/
   realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
   boolT DOcheckmax;       /* true if calling qh_check_maxout (qh_initqhull_globals) */
   char  *feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
   coordT *feasible_point;  /*    as coordinates, both malloc'd */
   boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */
   boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
   int   hull_dim;         /* dimension of hull, set by initbuffers */
   int   input_dim;        /* dimension of input, set by initbuffers */
   int   num_points;       /* number of input points */
   pointT *first_point;    /* array of input points, see POINTSmalloc */
   boolT POINTSmalloc;     /*   true if qh.first_point/num_points allocated */
   pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
   boolT input_malloc;     /* true if qh.input_points malloc'd */
   char  qhull_command[256];/* command line that invoked this program */
   int   qhull_commandsiz2; /*    size of qhull_command at qh_clear_outputflags */
   char  rbox_command[256]; /* command line that produced the input points */
   char  qhull_options[512];/* descriptive list of options */
   int   qhull_optionlen;  /*    length of last line */
   int   qhull_optionsiz;  /*    size of qhull_options at qh_build_withrestart */
   int   qhull_optionsiz2; /*    size of qhull_options at qh_clear_outputflags */
   int   run_id;           /* non-zero, random identifier for this instance of qhull */
   boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
   boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx'.  sets ZEROall_ok */
   realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
                              must set either GOODthreshold or SPLITthreshold
                              if Delaunay, default is 0.0 for upper envelope */
   realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
   realT *upper_bound;     /* scale point[k] to new upper bound */
   realT *lower_bound;     /* scale point[k] to new lower bound
                              project if both upper_ and lower_bound == 0 */
 
 /*----------------------------------
 
   qh precision constants
     precision constants for Qhull
 
   notes:
     qh_detroundoff() computes the maximum roundoff error for distance
     and other computations.  It also sets default values for the
     qh constants above.
 */
   realT ANGLEround;       /* max round off error for angles */
   realT centrum_radius;   /* max centrum radius for convexity (roundoff added) */
   realT cos_max;          /* max cosine for convexity (roundoff added) */
   realT DISTround;        /* max round off error for distances, 'E' overrides qh_distround() */
   realT MAXabs_coord;     /* max absolute coordinate */
   realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
   realT MAXsumcoord;      /* max sum of coordinates */
   realT MAXwidth;         /* max rectilinear width of point coordinates */
   realT MINdenom_1;       /* min. abs. value for 1/x */
   realT MINdenom;         /*    use divzero if denominator < MINdenom */
   realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
   realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
   realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
   boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
   realT *NEARzero;        /* hull_dim array for near zero in gausselim */
   realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
   realT ONEmerge;         /* max distance for merging simplicial facets */
   realT outside_err;      /* application's epsilon for coplanar points
                              qh_check_bestdist() qh_check_points() reports error if point outside */
   realT WIDEfacet;        /* size of wide facet for skipping ridge in
                              area computation and locking centrum */
 
 /*----------------------------------
 
   qh internal constants
     internal constants for Qhull
 */
   char qhull[sizeof("qhull")]; /* "qhull" for checking ownership while debugging */
   jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() */
   char jmpXtra[40];       /* extra bytes in case jmp_buf is defined wrong by compiler */
   jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() */
   char jmpXtra2[40];      /* extra bytes in case jmp_buf is defined wrong by compiler*/
   FILE *fin;              /* pointer to input file, init by qh_meminit */
   FILE *fout;             /* pointer to output file */
   FILE *ferr;             /* pointer to error file */
   pointT *interior_point; /* center point of the initial simplex*/
   int normal_size;     /* size in bytes for facet normals and point coords*/
   int center_size;     /* size in bytes for Voronoi centers */
   int   TEMPsize;         /* size for small, temporary sets (in quick mem) */
 
 /*----------------------------------
 
   qh facet and vertex lists
     defines lists of facets, new facets, visible facets, vertices, and
     new vertices.  Includes counts, next ids, and trace ids.
   see:
     qh_resetlists()
 */
   facetT *facet_list;     /* first facet */
   facetT  *facet_tail;     /* end of facet_list (dummy facet) */
   facetT *facet_next;     /* next facet for buildhull()
                              previous facets do not have outside sets
                              NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
   facetT *newfacet_list;  /* list of new facets to end of facet_list */
   facetT *visible_list;   /* list of visible facets preceeding newfacet_list,
                              facet->visible set */
   int       num_visible;  /* current number of visible facets */
   unsigned tracefacet_id;  /* set at init, then can print whenever */
   facetT *tracefacet;     /*   set in newfacet/mergefacet, undone in delfacet*/
   unsigned tracevertex_id;  /* set at buildtracing, can print whenever */
   vertexT *tracevertex;     /*   set in newvertex, undone in delvertex*/
   vertexT *vertex_list;     /* list of all vertices, to vertex_tail */
   vertexT  *vertex_tail;    /*      end of vertex_list (dummy vertex) */
   vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
                              all vertices have 'newlist' set */
   int   num_facets;       /* number of facets in facet_list
                              includes visble faces (num_visible) */
   int   num_vertices;     /* number of vertices in facet_list */
   int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
                                includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
   int   num_good;         /* number of good facets (after findgood_all) */
   unsigned facet_id;      /* ID of next, new facet from newfacet() */
   unsigned ridge_id:24;   /* ID of next, new ridge from newridge() */
   unsigned vertex_id:24;  /* ID of next, new vertex from newvertex() */
 
 /*----------------------------------
 
   qh global variables
     defines minimum and maximum distances, next visit ids, several flags,
     and other global variables.
     initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
 */
   unsigned long hulltime; /* ignore time to set up input and randomize */
                           /*   use unsigned to avoid wrap-around errors */
   boolT ALLOWrestart;     /* true if qh_precision can use qh.restartexit */
   int   build_cnt;        /* number of calls to qh_initbuild */
   qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
   int   furthest_id;      /* pointid of furthest point, for tracing */
   facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
   boolT hasAreaVolume;    /* true if totarea, totvol was defined by qh_getarea */
   boolT hasTriangulation; /* true if triangulation created by qh_triangulate */
   realT JOGGLEmax;        /* set 'QJn' if randomly joggle input */
   boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
   realT max_outside;      /* maximum distance from a point to a facet,
                                before roundoff, not simplicial vertices
                                actual outer plane is +DISTround and
                                computed outer plane is +2*DISTround */
   realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
                                before roundoff, due to a merge */
   realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
                                before roundoff, due to a merge
                                if qh.JOGGLEmax, qh_makenewplanes sets it
                                recomputed if qh.DOcheckmax, default -qh.DISTround */
   boolT NEWfacets;        /* true while visible facets invalid due to new or merge
                               from makecone/attachnewfacets to deletevisible */
   boolT findbestnew;      /* true if partitioning calls qh_findbestnew */
   boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
   boolT NOerrexit;        /* true if qh.errexit is not available */
   realT PRINTcradius;     /* radius for printing centrums */
   realT PRINTradius;      /* radius for printing vertex spheres and points */
   boolT POSTmerging;      /* true when post merging */
   int   printoutvar;      /* temporary variable for qh_printbegin, etc. */
   int   printoutnum;      /* number of facets printed */
   boolT QHULLfinished;    /* True after qhull() is finished */
   realT totarea;          /* 'FA': total facet area computed by qh_getarea, hasAreaVolume */
   realT totvol;           /* 'FA': total volume computed by qh_getarea, hasAreaVolume */
   unsigned int visit_id;  /* unique ID for searching neighborhoods, */
   unsigned int vertex_visit:31; /* unique ID for searching vertices, reset with qh_buildtracing */
   boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
   boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
 
 /*----------------------------------
 
   qh global sets
     defines sets for merging, initial simplex, hashing, extra input points,
     and deleted vertices
 */
   setT *facet_mergeset;   /* temporary set of merges to be done */
   setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
   setT *hash_table;       /* hash table for matching ridges in qh_matchfacets
                              size is setsize() */
   setT *other_points;     /* additional points */
   setT *del_vertices;     /* vertices to partition and delete with visible
                              facets.  Have deleted set for checkfacet */
 
 /*----------------------------------
 
   qh global buffers
     defines buffers for maxtrix operations, input, and error messages
 */
   coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom.c */
   coordT **gm_row;        /* array of gm_matrix rows */
   char* line;             /* malloc'd input line of maxline+1 chars */
   int maxline;
   coordT *half_space;     /* malloc'd input array for halfspace (qh normal_size+coordT) */
   coordT *temp_malloc;    /* malloc'd input array for points */
 
 /*----------------------------------
 
   qh static variables
     defines static variables for individual functions
 
   notes:
     do not use 'static' within a function.  Multiple instances of qhull
     may exist.
 
     do not assume zero initialization, 'QPn' may cause a restart
 */
   boolT ERREXITcalled;    /* true during qh_errexit (prevents duplicate calls */
   boolT firstcentrum;     /* for qh_printcentrum */
   boolT old_randomdist;   /* save RANDOMdist flag during io, tracing, or statistics */
   setT *coplanarfacetset;  /* set of coplanar facets for searching qh_findbesthorizon() */
   realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
   realT last_high;
   realT last_newhigh;
   unsigned lastreport;    /* for qh_buildtracing */
   int mergereport;        /* for qh_tracemerging */
   qhstatT *old_qhstat;    /* for saving qh_qhstat in save_qhull() and UsingLibQhull.  Free with qh_free() */
   setT *old_tempstack;    /* for saving qhmem.tempstack in save_qhull */
   int   ridgeoutnum;      /* number of ridges for 4OFF output (qh_printbegin,etc) */
 };
 
 /*=========== -macros- =========================*/
 
 /*----------------------------------
 
   otherfacet_(ridge, facet)
     return neighboring facet for a ridge in facet
 */
 #define otherfacet_(ridge, facet) \
                         (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
 
 /*----------------------------------
 
   getid_(p)
     return int ID for facet, ridge, or vertex
     return -1 if NULL
 */
 #define getid_(p)       ((p) ? (int)((p)->id) : -1)
 
 /*============== FORALL macros ===================*/
 
 /*----------------------------------
 
   FORALLfacets { ... }
     assign 'facet' to each facet in qh.facet_list
 
   notes:
     uses 'facetT *facet;'
     assumes last facet is a sentinel
 
   see:
     FORALLfacet_( facetlist )
 */
 #define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next)
 
 /*----------------------------------
 
   FORALLpoints { ... }
     assign 'point' to each point in qh.first_point, qh.num_points
 
   declare:
     coordT *point, *pointtemp;
 */
 #define FORALLpoints FORALLpoint_(qh first_point, qh num_points)
 
 /*----------------------------------
 
   FORALLpoint_( points, num) { ... }
     assign 'point' to each point in points array of num points
 
   declare:
     coordT *point, *pointtemp;
 */
 #define FORALLpoint_(points, num) for (point= (points), \
       pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim)
 
 /*----------------------------------
 
   FORALLvertices { ... }
     assign 'vertex' to each vertex in qh.vertex_list
 
   declare:
     vertexT *vertex;
 
   notes:
     assumes qh.vertex_list terminated with a sentinel
 */
 #define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)
 
 /*----------------------------------
 
   FOREACHfacet_( facets ) { ... }
     assign 'facet' to each facet in facets
 
   declare:
     facetT *facet, **facetp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
 
 /*----------------------------------
 
   FOREACHneighbor_( facet ) { ... }
     assign 'neighbor' to each neighbor in facet->neighbors
 
   FOREACHneighbor_( vertex ) { ... }
     assign 'neighbor' to each neighbor in vertex->neighbors
 
   declare:
     facetT *neighbor, **neighborp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
 
 /*----------------------------------
 
   FOREACHpoint_( points ) { ... }
     assign 'point' to each point in points set
 
   declare:
     pointT *point, **pointp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
 
 /*----------------------------------
 
   FOREACHridge_( ridges ) { ... }
     assign 'ridge' to each ridge in ridges set
 
   declare:
     ridgeT *ridge, **ridgep;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
 
 /*----------------------------------
 
   FOREACHvertex_( vertices ) { ... }
     assign 'vertex' to each vertex in vertices set
 
   declare:
     vertexT *vertex, **vertexp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
 
 /*----------------------------------
 
   FOREACHfacet_i_( facets ) { ... }
     assign 'facet' and 'facet_i' for each facet in facets set
 
   declare:
     facetT *facet;
     int     facet_n, facet_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHfacet_i_(facets)    FOREACHsetelement_i_(facetT, facets, facet)
 
 /*----------------------------------
 
   FOREACHneighbor_i_( facet ) { ... }
     assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
 
   FOREACHneighbor_i_( vertex ) { ... }
     assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors
 
   declare:
     facetT *neighbor;
     int     neighbor_n, neighbor_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHneighbor_i_(facet)  FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
 
 /*----------------------------------
 
   FOREACHpoint_i_( points ) { ... }
     assign 'point' and 'point_i' for each point in points set
 
   declare:
     pointT *point;
     int     point_n, point_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHpoint_i_(points)    FOREACHsetelement_i_(pointT, points, point)
 
 /*----------------------------------
 
   FOREACHridge_i_( ridges ) { ... }
     assign 'ridge' and 'ridge_i' for each ridge in ridges set
 
   declare:
     ridgeT *ridge;
     int     ridge_n, ridge_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHridge_i_(ridges)    FOREACHsetelement_i_(ridgeT, ridges, ridge)
 
 /*----------------------------------
 
   FOREACHvertex_i_( vertices ) { ... }
     assign 'vertex' and 'vertex_i' for each vertex in vertices set
 
   declare:
     vertexT *vertex;
     int     vertex_n, vertex_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
 
 /********* -libqhull.c prototypes (duplicated from qhull_a.h) **********************/
 
 void    qh_qhull(void);
 boolT   qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist);
 void    qh_printsummary(FILE *fp);
 
 /********* -user.c prototypes (alphabetical) **********************/
 
 void    qh_errexit(int exitcode, facetT *facet, ridgeT *ridge);
 void    qh_errprint(const char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
 int     qh_new_qhull(int dim, int numpoints, coordT *points, boolT ismalloc,
                 char *qhull_cmd, FILE *outfile, FILE *errfile);
 void    qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall);
 void    qh_printhelp_degenerate(FILE *fp);
 void    qh_printhelp_narrowhull(FILE *fp, realT minangle);
 void    qh_printhelp_singular(FILE *fp);
 void    qh_user_memsizes(void);
 
 /********* -usermem.c prototypes (alphabetical) **********************/
 void    qh_exit(int exitcode);
 void    qh_free(void *mem);
 void   *qh_malloc(size_t size);
 
 /********* -userprintf.c and userprintf_rbox.c prototypes **********************/
 void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
 void    qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... );
 
 /***** -geom.c/geom2.c/random.c prototypes (duplicated from geom.h, random.h) ****************/
 
 facetT *qh_findbest(pointT *point, facetT *startfacet,
                      boolT bestoutside, boolT newfacets, boolT noupper,
                      realT *dist, boolT *isoutside, int *numpart);
 facetT *qh_findbestnew(pointT *point, facetT *startfacet,
                      realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
 boolT   qh_gram_schmidt(int dim, realT **rows);
 void    qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane);
 void    qh_printsummary(FILE *fp);
 void    qh_projectinput(void);
 void    qh_randommatrix(realT *buffer, int dim, realT **row);
 void    qh_rotateinput(realT **rows);
 void    qh_scaleinput(void);
 void    qh_setdelaunay(int dim, int count, pointT *points);
 coordT  *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible);
 
 /***** -global.c prototypes (alphabetical) ***********************/
 
 unsigned long qh_clock(void);
 void    qh_checkflags(char *command, char *hiddenflags);
 void    qh_clear_outputflags(void);
 void    qh_freebuffers(void);
 void    qh_freeqhull(boolT allmem);
 void    qh_freeqhull2(boolT allmem);
 void    qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
 void    qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc);
 void    qh_init_qhull_command(int argc, char *argv[]);
 void    qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);
 void    qh_initflags(char *command);
 void    qh_initqhull_buffers(void);
 void    qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc);
 void    qh_initqhull_mem(void);
 void    qh_initqhull_outputflags(void);
 void    qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile);
 void    qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile);
 void    qh_initthresholds(char *command);
 void    qh_option(const char *option, int *i, realT *r);
 #if qh_QHpointer
 void    qh_restore_qhull(qhT **oldqh);
 qhT    *qh_save_qhull(void);
 #endif
 
 /***** -io.c prototypes (duplicated from io.h) ***********************/
 
 void    qh_dfacet( unsigned id);
 void    qh_dvertex( unsigned id);
 void    qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
 void    qh_produce_output(void);
 coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
 
 
 /********* -mem.c prototypes (duplicated from mem.h) **********************/
 
 void qh_meminit(FILE *ferr);
 void qh_memfreeshort(int *curlong, int *totlong);
 
 /********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/
 
 void    qh_check_output(void);
 void    qh_check_points(void);
 setT   *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets);
 facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
            realT *bestdist, boolT *isoutside);
 vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp);
 pointT *qh_point(int id);
 setT   *qh_pointfacet(void /*qh.facet_list*/);
 int     qh_pointid(pointT *point);
 setT   *qh_pointvertex(void /*qh.facet_list*/);
 void    qh_setvoronoi_all(void);
 void    qh_triangulate(void /*qh.facet_list*/);
 
 /********* -rboxpoints.c prototypes **********************/
 int     qh_rboxpoints(FILE* fout, FILE* ferr, char* rbox_command);
 void    qh_errexit_rbox(int exitcode);
 
 /********* -stat.c prototypes (duplicated from stat.h) **********************/
 
 void    qh_collectstatistics(void);
 void    qh_printallstatistics(FILE *fp, const char *string);
 
 #endif /* qhDEFlibqhull */
diff --git a/src/libqhull/mem.c b/src/libqhull/mem.c
index 5b63f86..5c724be 100644
--- a/src/libqhull/mem.c
+++ b/src/libqhull/mem.c
@@ -1,549 +1,549 @@
 /*
  ---------------------------------
 
   mem.c
     memory management routines for qhull
 
   This is a standalone program.
 
   To initialize memory:
 
     qh_meminit(stderr);
     qh_meminitbuffers(qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
     qh_memsize((int)sizeof(facetT));
     qh_memsize((int)sizeof(facetT));
     ...
     qh_memsetup();
 
   To free up all memory buffers:
     qh_memfreeshort(&curlong, &totlong);
 
   if qh_NOmem,
     malloc/free is used instead of mem.c
 
   notes:
     uses Quickfit algorithm (freelists for commonly allocated sizes)
     assumes small sizes for freelists (it discards the tail of memory buffers)
 
   see:
     qh-mem.htm and mem.h
     global.c (qh_initbuffers) for an example of using mem.c
 
-  Copyright (c) 1993-2014 The Geometry Center.
-  $Id: //main/2011/qhull/src/libqhull/mem.c#5 $$Change: 1645 $
-  $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+  Copyright (c) 1993-2015 The Geometry Center.
+  $Id: //main/2011/qhull/src/libqhull/mem.c#7 $$Change: 1810 $
+  $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "mem.h"
 #include 
 #include 
 #include 
 
 #ifndef qhDEFlibqhull
 typedef struct ridgeT ridgeT;
 typedef struct facetT facetT;
 #ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
 #pragma warning( disable : 4127)  /* conditional expression is constant */
 #pragma warning( disable : 4706)  /* assignment within conditional function */
 #endif
 void    qh_errexit(int exitcode, facetT *, ridgeT *);
 void    qh_exit(int exitcode);
 void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
 void    qh_free(void *mem);
 void   *qh_malloc(size_t size);
 #endif
 
 /*============ -global data structure ==============
     see mem.h for definition
 */
 
 qhmemT qhmem= {0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0};     /* remove "= {0}" if this causes a compiler error */
 
 #ifndef qh_NOmem
 
 /*============= internal functions ==============*/
 
 static int qh_intcompare(const void *i, const void *j);
 
 /*========== functions in alphabetical order ======== */
 
 /*---------------------------------
 
   qh_intcompare( i, j )
     used by qsort and bsearch to compare two integers
 */
 static int qh_intcompare(const void *i, const void *j) {
   return(*((const int *)i) - *((const int *)j));
 } /* intcompare */
 
 
 /*----------------------------------
 
   qh_memalloc( insize )
     returns object of insize bytes
     qhmem is the global memory structure
 
   returns:
     pointer to allocated memory
     errors if insufficient memory
 
   notes:
     use explicit type conversion to avoid type warnings on some compilers
     actual object may be larger than insize
     use qh_memalloc_() for inline code for quick allocations
     logs allocations if 'T5'
 
   design:
     if size < qhmem.LASTsize
       if qhmem.freelists[size] non-empty
         return first object on freelist
       else
         round up request to size of qhmem.freelists[size]
         allocate new allocation buffer if necessary
         allocate object from allocation buffer
     else
       allocate object with qh_malloc() in user.c
 */
 void *qh_memalloc(int insize) {
   void **freelistp, *newbuffer;
   int idx, size, n;
   int outsize, bufsize;
   void *object;
 
   if (insize<0) {
       qh_fprintf(qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d).  Did int overflow due to high-D?\n", insize); /* WARN64 */
       qh_errexit(qhmem_ERRmem, NULL, NULL);
   }
   if (insize>=0 && insize <= qhmem.LASTsize) {
     idx= qhmem.indextable[insize];
     outsize= qhmem.sizetable[idx];
     qhmem.totshort += outsize;
     freelistp= qhmem.freelists+idx;
     if ((object= *freelistp)) {
       qhmem.cntquick++;
       qhmem.totfree -= outsize;
       *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
 #ifdef qh_TRACEshort
       n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
       if (qhmem.IStracing >= 5)
           qh_fprintf(qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
 #endif
       return(object);
     }else {
       qhmem.cntshort++;
       if (outsize > qhmem.freesize) {
         qhmem.totdropped += qhmem.freesize;
         if (!qhmem.curbuffer)
           bufsize= qhmem.BUFinit;
         else
           bufsize= qhmem.BUFsize;
         if (!(newbuffer= qh_malloc((size_t)bufsize))) {
           qh_fprintf(qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
           qh_errexit(qhmem_ERRmem, NULL, NULL);
         }
         *((void **)newbuffer)= qhmem.curbuffer;  /* prepend newbuffer to curbuffer
                                                     list */
         qhmem.curbuffer= newbuffer;
         size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
         qhmem.freemem= (void *)((char *)newbuffer+size);
         qhmem.freesize= bufsize - size;
         qhmem.totbuffer += bufsize - size; /* easier to check */
         /* Periodically test totbuffer.  It matches at beginning and exit of every call */
         n = qhmem.totshort + qhmem.totfree + qhmem.totdropped + qhmem.freesize - outsize;
         if (qhmem.totbuffer != n) {
             qh_fprintf(qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qhmem.totbuffer, n);
             qh_errexit(qhmem_ERRmem, NULL, NULL);
         }
       }
       object= qhmem.freemem;
       qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
       qhmem.freesize -= outsize;
       qhmem.totunused += outsize - insize;
 #ifdef qh_TRACEshort
       n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
       if (qhmem.IStracing >= 5)
           qh_fprintf(qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
 #endif
       return object;
     }
   }else {                     /* long allocation */
     if (!qhmem.indextable) {
       qh_fprintf(qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
       qh_errexit(qhmem_ERRqhull, NULL, NULL);
     }
     outsize= insize;
     qhmem.cntlong++;
     qhmem.totlong += outsize;
     if (qhmem.maxlong < qhmem.totlong)
       qhmem.maxlong= qhmem.totlong;
     if (!(object= qh_malloc((size_t)outsize))) {
       qh_fprintf(qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
       qh_errexit(qhmem_ERRmem, NULL, NULL);
     }
     if (qhmem.IStracing >= 5)
       qh_fprintf(qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, outsize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
   }
   return(object);
 } /* memalloc */
 
 
 /*----------------------------------
 
   qh_memfree( object, insize )
     free up an object of size bytes
     size is insize from qh_memalloc
 
   notes:
     object may be NULL
     type checking warns if using (void **)object
     use qh_memfree_() for quick free's of small objects
 
   design:
     if size <= qhmem.LASTsize
       append object to corresponding freelist
     else
       call qh_free(object)
 */
 void qh_memfree(void *object, int insize) {
   void **freelistp;
   int idx, outsize;
 
   if (!object)
     return;
   if (insize <= qhmem.LASTsize) {
     qhmem.freeshort++;
     idx= qhmem.indextable[insize];
     outsize= qhmem.sizetable[idx];
     qhmem.totfree += outsize;
     qhmem.totshort -= outsize;
     freelistp= qhmem.freelists + idx;
     *((void **)object)= *freelistp;
     *freelistp= object;
 #ifdef qh_TRACEshort
     idx= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
     if (qhmem.IStracing >= 5)
         qh_fprintf(qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
 #endif
   }else {
     qhmem.freelong++;
     qhmem.totlong -= insize;
     qh_free(object);
     if (qhmem.IStracing >= 5)
       qh_fprintf(qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
   }
 } /* memfree */
 
 
 /*---------------------------------
 
   qh_memfreeshort( curlong, totlong )
     frees up all short and qhmem memory allocations
 
   returns:
     number and size of current long allocations
 
   see:
     qh_freeqhull(allMem)
     qh_memtotal(curlong, totlong, curshort, totshort, maxlong, totbuffer);
 */
 void qh_memfreeshort(int *curlong, int *totlong) {
   void *buffer, *nextbuffer;
   FILE *ferr;
 
   *curlong= qhmem.cntlong - qhmem.freelong;
   *totlong= qhmem.totlong;
   for (buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
     nextbuffer= *((void **) buffer);
     qh_free(buffer);
   }
   qhmem.curbuffer= NULL;
   if (qhmem.LASTsize) {
     qh_free(qhmem.indextable);
     qh_free(qhmem.freelists);
     qh_free(qhmem.sizetable);
   }
   ferr= qhmem.ferr;
   memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
   qhmem.ferr= ferr;
 } /* memfreeshort */
 
 
 /*----------------------------------
 
   qh_meminit( ferr )
     initialize qhmem and test sizeof( void*)
 */
 void qh_meminit(FILE *ferr) {
 
   memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
   if (ferr)
     qhmem.ferr= ferr;
   else
     qhmem.ferr= stderr;
   if (sizeof(void*) < sizeof(int)) {
     qh_fprintf(qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
     qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
   }
   if (sizeof(void*) > sizeof(ptr_intT)) {
       qh_fprintf(qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
       qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
   }
 } /* meminit */
 
 /*---------------------------------
 
   qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit )
     initialize qhmem
     if tracelevel >= 5, trace memory allocations
     alignment= desired address alignment for memory allocations
     numsizes= number of freelists
     bufsize=  size of additional memory buffers for short allocations
     bufinit=  size of initial memory buffer for short allocations
 */
 void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
 
   qhmem.IStracing= tracelevel;
   qhmem.NUMsizes= numsizes;
   qhmem.BUFsize= bufsize;
   qhmem.BUFinit= bufinit;
   qhmem.ALIGNmask= alignment-1;
   if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) {
     qh_fprintf(qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
   qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
   if (!qhmem.sizetable || !qhmem.freelists) {
     qh_fprintf(qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
     qh_errexit(qhmem_ERRmem, NULL, NULL);
   }
   if (qhmem.IStracing >= 1)
     qh_fprintf(qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
 } /* meminitbuffers */
 
 /*---------------------------------
 
   qh_memsetup()
     set up memory after running memsize()
 */
 void qh_memsetup(void) {
   int k,i;
 
   qsort(qhmem.sizetable, (size_t)qhmem.TABLEsize, sizeof(int), qh_intcompare);
   qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
   if (qhmem.LASTsize >= qhmem.BUFsize || qhmem.LASTsize >= qhmem.BUFinit) {
     qh_fprintf(qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
             qhmem.LASTsize, qhmem.BUFsize, qhmem.BUFinit);
     qh_errexit(qhmem_ERRmem, NULL, NULL);
   }
   if (!(qhmem.indextable= (int *)qh_malloc((qhmem.LASTsize+1) * sizeof(int)))) {
     qh_fprintf(qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
     qh_errexit(qhmem_ERRmem, NULL, NULL);
   }
   for (k=qhmem.LASTsize+1; k--; )
     qhmem.indextable[k]= k;
   i= 0;
   for (k=0; k <= qhmem.LASTsize; k++) {
     if (qhmem.indextable[k] <= qhmem.sizetable[i])
       qhmem.indextable[k]= i;
     else
       qhmem.indextable[k]= ++i;
   }
 } /* memsetup */
 
 /*---------------------------------
 
   qh_memsize( size )
     define a free list for this size
 */
 void qh_memsize(int size) {
   int k;
 
   if (qhmem.LASTsize) {
     qh_fprintf(qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n");
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
   for (k=qhmem.TABLEsize; k--; ) {
     if (qhmem.sizetable[k] == size)
       return;
   }
   if (qhmem.TABLEsize < qhmem.NUMsizes)
     qhmem.sizetable[qhmem.TABLEsize++]= size;
   else
     qh_fprintf(qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
 } /* memsize */
 
 
 /*---------------------------------
 
   qh_memstatistics( fp )
     print out memory statistics
 
     Verifies that qhmem.totfree == sum of freelists
 */
 void qh_memstatistics(FILE *fp) {
   int i, count, totfree= 0;
   void *object;
 
   for (i=0; i < qhmem.TABLEsize; i++) {
     count=0;
     for (object= qhmem.freelists[i]; object; object= *((void **)object))
       count++;
     totfree += qhmem.sizetable[i] * count;
   }
   if (totfree != qhmem.totfree) {
       qh_fprintf(qhmem.ferr, 6211, "qh_memstatistics internal error: totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree);
       qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   qh_fprintf(fp, 9278, "\nmemory statistics:\n\
 %7d quick allocations\n\
 %7d short allocations\n\
 %7d long allocations\n\
 %7d short frees\n\
 %7d long frees\n\
 %7d bytes of short memory in use\n\
 %7d bytes of short memory in freelists\n\
 %7d bytes of dropped short memory\n\
 %7d bytes of unused short memory (estimated)\n\
 %7d bytes of long memory allocated (max, except for input)\n\
 %7d bytes of long memory in use (in %d pieces)\n\
 %7d bytes of short memory buffers (minus links)\n\
 %7d bytes per short memory buffer (initially %d bytes)\n",
            qhmem.cntquick, qhmem.cntshort, qhmem.cntlong,
            qhmem.freeshort, qhmem.freelong,
            qhmem.totshort, qhmem.totfree,
            qhmem.totdropped + qhmem.freesize, qhmem.totunused,
            qhmem.maxlong, qhmem.totlong, qhmem.cntlong - qhmem.freelong,
            qhmem.totbuffer, qhmem.BUFsize, qhmem.BUFinit);
   if (qhmem.cntlarger) {
     qh_fprintf(fp, 9279, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
            qhmem.cntlarger, ((float)qhmem.totlarger)/(float)qhmem.cntlarger);
     qh_fprintf(fp, 9280, "  freelists(bytes->count):");
   }
   for (i=0; i < qhmem.TABLEsize; i++) {
     count=0;
     for (object= qhmem.freelists[i]; object; object= *((void **)object))
       count++;
     qh_fprintf(fp, 9281, " %d->%d", qhmem.sizetable[i], count);
   }
   qh_fprintf(fp, 9282, "\n\n");
 } /* memstatistics */
 
 
 /*---------------------------------
 
   qh_NOmem
     turn off quick-fit memory allocation
 
   notes:
     uses qh_malloc() and qh_free() instead
 */
 #else /* qh_NOmem */
 
 void *qh_memalloc(int insize) {
   void *object;
 
   if (!(object= qh_malloc((size_t)insize))) {
     qh_fprintf(qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
     qh_errexit(qhmem_ERRmem, NULL, NULL);
   }
   qhmem.cntlong++;
   qhmem.totlong += insize;
   if (qhmem.maxlong < qhmem.totlong)
       qhmem.maxlong= qhmem.totlong;
   if (qhmem.IStracing >= 5)
     qh_fprintf(qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
   return object;
 }
 
 void qh_memfree(void *object, int insize) {
 
   if (!object)
     return;
   qh_free(object);
   qhmem.freelong++;
   qhmem.totlong -= insize;
   if (qhmem.IStracing >= 5)
     qh_fprintf(qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
 }
 
 void qh_memfreeshort(int *curlong, int *totlong) {
   *totlong= qhmem.totlong;
   *curlong= qhmem.cntlong - qhmem.freelong;
   memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
 }
 
 void qh_meminit(FILE *ferr) {
 
   memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
   if (ferr)
       qhmem.ferr= ferr;
   else
       qhmem.ferr= stderr;
   if (sizeof(void*) < sizeof(int)) {
     qh_fprintf(qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
 }
 
 void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
 
   qhmem.IStracing= tracelevel;
 }
 
 void qh_memsetup(void) {
 
 }
 
 void qh_memsize(int size) {
 
 }
 
 void qh_memstatistics(FILE *fp) {
 
   qh_fprintf(fp, 9409, "\nmemory statistics:\n\
 %7d long allocations\n\
 %7d long frees\n\
 %7d bytes of long memory allocated (max, except for input)\n\
 %7d bytes of long memory in use (in %d pieces)\n",
            qhmem.cntlong,
            qhmem.freelong,
            qhmem.maxlong, qhmem.totlong, qhmem.cntlong - qhmem.freelong);
 }
 
 #endif /* qh_NOmem */
 
 /*---------------------------------
 
   qh_memtotal( totlong, curlong, totshort, curshort, maxlong, totbuffer )
     Return the total, allocated long and short memory
 
   returns:
     Returns the total current bytes of long and short allocations
     Returns the current count of long and short allocations
     Returns the maximum long memory and total short buffer (minus one link per buffer)
     Does not error (UsingLibQhull.cpp)
 */
 void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
     *totlong= qhmem.totlong;
     *curlong= qhmem.cntlong - qhmem.freelong;
     *totshort= qhmem.totshort;
     *curshort= qhmem.cntshort + qhmem.cntquick - qhmem.freeshort;
     *maxlong= qhmem.maxlong;
     *totbuffer= qhmem.totbuffer;
 } /* memtotlong */
 
diff --git a/src/libqhull/mem.h b/src/libqhull/mem.h
index f7c14d1..b7f4a4d 100644
--- a/src/libqhull/mem.h
+++ b/src/libqhull/mem.h
@@ -1,219 +1,219 @@
 /*
  ---------------------------------
 
    mem.h
      prototypes for memory management functions
 
    see qh-mem.htm, mem.c and qset.h
 
    for error handling, writes message and calls
      qh_errexit(qhmem_ERRmem, NULL, NULL) if insufficient memory
        and
      qh_errexit(qhmem_ERRqhull, NULL, NULL) otherwise
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/mem.h#5 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/mem.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFmem
 #define qhDEFmem 1
 
 #include 
 
 /*---------------------------------
 
   qh_NOmem
     turn off quick-fit memory allocation
 
   notes:
     mem.c implements Quickfit memory allocation for about 20% time
     savings.  If it fails on your machine, try to locate the
     problem, and send the answer to qhull@qhull.org.  If this can
     not be done, define qh_NOmem to use malloc/free instead.
 
    #define qh_NOmem
 */
 
 /*---------------------------------
 
 qh_TRACEshort
 Trace short and quick memory allocations at T5
 
 */
 #define qh_TRACEshort
 
 /*-------------------------------------------
     to avoid bus errors, memory allocation must consider alignment requirements.
     malloc() automatically takes care of alignment.   Since mem.c manages
     its own memory, we need to explicitly specify alignment in
     qh_meminitbuffers().
 
     A safe choice is sizeof(double).  sizeof(float) may be used if doubles
     do not occur in data structures and pointers are the same size.  Be careful
     of machines (e.g., DEC Alpha) with large pointers.  If gcc is available,
     use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
 
    see qh_MEMalign in user.h for qhull's alignment
 */
 
 #define qhmem_ERRmem 4    /* matches qh_ERRmem in libqhull.h */
 #define qhmem_ERRqhull 5  /* matches qh_ERRqhull in libqhull.h */
 
 /*----------------------------------
 
   ptr_intT
     for casting a void * to an integer-type that holds a pointer
     Used for integer expressions (e.g., computing qh_gethash() in poly.c)
 
   notes:
     WARN64 -- these notes indicate 64-bit issues
     On 64-bit machines, a pointer may be larger than an 'int'.
     qh_meminit()/mem.c checks that 'ptr_intT' holds a 'void*'
     ptr_intT is typically a signed value, but not necessarily so
     size_t is typically unsigned, but should match the parameter type
     Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
     This matches Qt convention and is easier to work with.  
 */
 #if _MSC_VER && defined(_WIN64)
 typedef long long ptr_intT;
 #else
 typedef long ptr_intT;
 #endif
 
 /*----------------------------------
 
   qhmemT
     global memory structure for mem.c
 
  notes:
    users should ignore qhmem except for writing extensions
    qhmem is allocated in mem.c
 
    qhmem could be swapable like qh and qhstat, but then
    multiple qh's and qhmem's would need to keep in synch.
    A swapable qhmem would also waste memory buffers.  As long
    as memory operations are atomic, there is no problem with
    multiple qh structures being active at the same time.
    If you need separate address spaces, you can swap the
    contents of qhmem.
 */
 typedef struct qhmemT qhmemT;
 extern qhmemT qhmem;
 
 #ifndef DEFsetT
 #define DEFsetT 1
 typedef struct setT setT;          /* defined in qset.h */
 #endif
 
 /* Update qhmem in mem.c if add or remove fields */
 struct qhmemT {               /* global memory management variables */
   int      BUFsize;           /* size of memory allocation buffer */
   int      BUFinit;           /* initial size of memory allocation buffer */
   int      TABLEsize;         /* actual number of sizes in free list table */
   int      NUMsizes;          /* maximum number of sizes in free list table */
   int      LASTsize;          /* last size in free list table */
   int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
   void   **freelists;          /* free list table, linked by offset 0 */
   int     *sizetable;         /* size of each freelist */
   int     *indextable;        /* size->index table */
   void    *curbuffer;         /* current buffer, linked by offset 0 */
   void    *freemem;           /*   free memory in curbuffer */
   int      freesize;          /*   size of freemem in bytes */
   setT    *tempstack;         /* stack of temporary memory, managed by users */
   FILE    *ferr;              /* file for reporting errors when 'qh' may be undefined */
   int      IStracing;         /* =5 if tracing memory allocations */
   int      cntquick;          /* count of quick allocations */
                               /* Note: removing statistics doesn't effect speed */
   int      cntshort;          /* count of short allocations */
   int      cntlong;           /* count of long allocations */
   int      freeshort;         /* count of short memfrees */
   int      freelong;          /* count of long memfrees */
   int      totbuffer;         /* total short memory buffers minus buffer links */
   int      totdropped;        /* total dropped memory at end of short memory buffers (e.g., freesize) */
   int      totfree;           /* total size of free, short memory on freelists */
   int      totlong;           /* total size of long memory in use */
   int      maxlong;           /*   maximum totlong */
   int      totshort;          /* total size of short memory in use */
   int      totunused;         /* total unused short memory (estimated, short size - request size of first allocations) */
   int      cntlarger;         /* count of setlarger's */
   int      totlarger;         /* total copied by setlarger */
 };
 
 
 /*==================== -macros ====================*/
 
 /*----------------------------------
 
   qh_memalloc_(insize, freelistp, object, type)
     returns object of size bytes
         assumes size<=qhmem.LASTsize and void **freelistp is a temp
 */
 
 #if defined qh_NOmem
 #define qh_memalloc_(insize, freelistp, object, type) {\
   object= (type*)qh_memalloc(insize); }
 #elif defined qh_TRACEshort
 #define qh_memalloc_(insize, freelistp, object, type) {\
     freelistp= NULL; /* Avoid warnings */ \
     object= (type*)qh_memalloc(insize); }
 #else /* !qh_NOmem */
 
 #define qh_memalloc_(insize, freelistp, object, type) {\
   freelistp= qhmem.freelists + qhmem.indextable[insize];\
   if ((object= (type*)*freelistp)) {\
     qhmem.totshort += qhmem.sizetable[qhmem.indextable[insize]]; \
     qhmem.totfree -= qhmem.sizetable[qhmem.indextable[insize]]; \
     qhmem.cntquick++;  \
     *freelistp= *((void **)*freelistp);\
   }else object= (type*)qh_memalloc(insize);}
 #endif
 
 /*----------------------------------
 
   qh_memfree_(object, insize, freelistp)
     free up an object
 
   notes:
     object may be NULL
     assumes size<=qhmem.LASTsize and void **freelistp is a temp
 */
 #if defined qh_NOmem
 #define qh_memfree_(object, insize, freelistp) {\
   qh_memfree(object, insize); }
 #elif defined qh_TRACEshort
 #define qh_memfree_(object, insize, freelistp) {\
     freelistp= NULL; /* Avoid warnings */ \
     qh_memfree(object, insize); }
 #else /* !qh_NOmem */
 
 #define qh_memfree_(object, insize, freelistp) {\
   if (object) { \
     qhmem.freeshort++;\
     freelistp= qhmem.freelists + qhmem.indextable[insize];\
     qhmem.totshort -= qhmem.sizetable[qhmem.indextable[insize]]; \
     qhmem.totfree += qhmem.sizetable[qhmem.indextable[insize]]; \
     *((void **)object)= *freelistp;\
     *freelistp= object;}}
 #endif
 
 /*=============== prototypes in alphabetical order ============*/
 
 void *qh_memalloc(int insize);
 void qh_memfree(void *object, int insize);
 void qh_memfreeshort(int *curlong, int *totlong);
 void qh_meminit(FILE *ferr);
 void qh_meminitbuffers(int tracelevel, int alignment, int numsizes,
                         int bufsize, int bufinit);
 void qh_memsetup(void);
 void qh_memsize(int size);
 void qh_memstatistics(FILE *fp);
 void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer);
 
 #endif /* qhDEFmem */
diff --git a/src/libqhull/merge.c b/src/libqhull/merge.c
index 4f7f358..6a4e542 100644
--- a/src/libqhull/merge.c
+++ b/src/libqhull/merge.c
@@ -1,3623 +1,3623 @@
 /*
  ---------------------------------
 
    merge.c
    merges non-convex facets
 
    see qh-merge.htm and merge.h
 
    other modules call qh_premerge() and qh_postmerge()
 
    the user may call qh_postmerge() to perform additional merges.
 
    To remove deleted facets and vertices (qhull() in libqhull.c):
      qh_partitionvisible(!qh_ALL, &numoutside);  // visible_list, newfacet_list
      qh_deletevisible();         // qh.visible_list
      qh_resetlists(False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list
 
    assumes qh.CENTERtype= centrum
 
    merges occur in qh_mergefacet and in qh_mergecycle
    vertex->neighbors not set until the first merge occurs
 
-   Copyright (c) 1993-2014 C.B. Barber.
-   $Id: //main/2011/qhull/src/libqhull/merge.c#5 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 C.B. Barber.
+   $Id: //main/2011/qhull/src/libqhull/merge.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_a.h"
 
 #ifndef qh_NOmerge
 
 /*===== functions(alphabetical after premerge and postmerge) ======*/
 
 /*---------------------------------
 
   qh_premerge( apex, maxcentrum )
     pre-merge nonconvex facets in qh.newfacet_list for apex
     maxcentrum defines coplanar and concave (qh_test_appendmerge)
 
   returns:
     deleted facets added to qh.visible_list with facet->visible set
 
   notes:
     uses globals, qh.MERGEexact, qh.PREmerge
 
   design:
     mark duplicate ridges in qh.newfacet_list
     merge facet cycles in qh.newfacet_list
     merge duplicate ridges and concave facets in qh.newfacet_list
     check merged facet cycles for degenerate and redundant facets
     merge degenerate and redundant facets
     collect coplanar and concave facets
     merge concave, coplanar, degenerate, and redundant facets
 */
 void qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle) {
   boolT othermerge= False;
   facetT *newfacet;
 
   if (qh ZEROcentrum && qh_checkzero(!qh_ALL))
     return;
   trace2((qh ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",
             maxcentrum, maxangle, apex->id, getid_(qh newfacet_list)));
   if (qh IStracing >= 4 && qh num_facets < 50)
     qh_printlists();
   qh centrum_radius= maxcentrum;
   qh cos_max= maxangle;
   qh degen_mergeset= qh_settemp(qh TEMPsize);
   qh facet_mergeset= qh_settemp(qh TEMPsize);
   if (qh hull_dim >=3) {
     qh_mark_dupridges(qh newfacet_list); /* facet_mergeset */
     qh_mergecycle_all(qh newfacet_list, &othermerge);
     qh_forcedmerges(&othermerge /* qh.facet_mergeset */);
     FORALLnew_facets {  /* test samecycle merges */
       if (!newfacet->simplicial && !newfacet->mergeridge)
         qh_degen_redundant_neighbors(newfacet, NULL);
     }
     if (qh_merge_degenredundant())
       othermerge= True;
   }else /* qh.hull_dim == 2 */
     qh_mergecycle_all(qh newfacet_list, &othermerge);
   qh_flippedmerges(qh newfacet_list, &othermerge);
   if (!qh MERGEexact || zzval_(Ztotmerge)) {
     zinc_(Zpremergetot);
     qh POSTmerging= False;
     qh_getmergeset_initial(qh newfacet_list);
     qh_all_merges(othermerge, False);
   }
   qh_settempfree(&qh facet_mergeset);
   qh_settempfree(&qh degen_mergeset);
 } /* premerge */
 
 /*---------------------------------
 
   qh_postmerge( reason, maxcentrum, maxangle, vneighbors )
     post-merge nonconvex facets as defined by maxcentrum and maxangle
     'reason' is for reporting progress
     if vneighbors,
       calls qh_test_vneighbors at end of qh_all_merge
     if firstmerge,
       calls qh_reducevertices before qh_getmergeset
 
   returns:
     if first call (qh.visible_list != qh.facet_list),
       builds qh.facet_newlist, qh.newvertex_list
     deleted facets added to qh.visible_list with facet->visible
     qh.visible_list == qh.facet_list
 
   notes:
 
 
   design:
     if first call
       set qh.visible_list and qh.newfacet_list to qh.facet_list
       add all facets to qh.newfacet_list
       mark non-simplicial facets, facet->newmerge
       set qh.newvertext_list to qh.vertex_list
       add all vertices to qh.newvertex_list
       if a pre-merge occured
         set vertex->delridge {will retest the ridge}
         if qh.MERGEexact
           call qh_reducevertices()
       if no pre-merging
         merge flipped facets
     determine non-convex facets
     merge all non-convex facets
 */
 void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
                       boolT vneighbors) {
   facetT *newfacet;
   boolT othermerges= False;
   vertexT *vertex;
 
   if (qh REPORTfreq || qh IStracing) {
     qh_buildtracing(NULL, NULL);
     qh_printsummary(qh ferr);
     if (qh PRINTstatistics)
       qh_printallstatistics(qh ferr, "reason");
     qh_fprintf(qh ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",
         reason, maxcentrum, maxangle);
   }
   trace2((qh ferr, 2009, "qh_postmerge: postmerge.  test vneighbors? %d\n",
             vneighbors));
   qh centrum_radius= maxcentrum;
   qh cos_max= maxangle;
   qh POSTmerging= True;
   qh degen_mergeset= qh_settemp(qh TEMPsize);
   qh facet_mergeset= qh_settemp(qh TEMPsize);
   if (qh visible_list != qh facet_list) {  /* first call */
     qh NEWfacets= True;
     qh visible_list= qh newfacet_list= qh facet_list;
     FORALLnew_facets {
       newfacet->newfacet= True;
        if (!newfacet->simplicial)
         newfacet->newmerge= True;
      zinc_(Zpostfacets);
     }
     qh newvertex_list= qh vertex_list;
     FORALLvertices
       vertex->newlist= True;
     if (qh VERTEXneighbors) { /* a merge has occurred */
       FORALLvertices
         vertex->delridge= True; /* test for redundant, needed? */
       if (qh MERGEexact) {
         if (qh hull_dim <= qh_DIMreduceBuild)
           qh_reducevertices(); /* was skipped during pre-merging */
       }
     }
     if (!qh PREmerge && !qh MERGEexact)
       qh_flippedmerges(qh newfacet_list, &othermerges);
   }
   qh_getmergeset_initial(qh newfacet_list);
   qh_all_merges(False, vneighbors);
   qh_settempfree(&qh facet_mergeset);
   qh_settempfree(&qh degen_mergeset);
 } /* post_merge */
 
 /*---------------------------------
 
   qh_all_merges( othermerge, vneighbors )
     merge all non-convex facets
 
     set othermerge if already merged facets (for qh_reducevertices)
     if vneighbors
       tests vertex neighbors for convexity at end
     qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
     qh.degen_mergeset is defined
     if qh.MERGEexact && !qh.POSTmerging,
       does not merge coplanar facets
 
   returns:
     deleted facets added to qh.visible_list with facet->visible
     deleted vertices added qh.delvertex_list with vertex->delvertex
 
   notes:
     unless !qh.MERGEindependent,
       merges facets in independent sets
     uses qh.newfacet_list as argument since merges call qh_removefacet()
 
   design:
     while merges occur
       for each merge in qh.facet_mergeset
         unless one of the facets was already merged in this pass
           merge the facets
         test merged facets for additional merges
         add merges to qh.facet_mergeset
       if vertices record neighboring facets
         rename redundant vertices
           update qh.facet_mergeset
     if vneighbors ??
       tests vertex neighbors for convexity at end
 */
 void qh_all_merges(boolT othermerge, boolT vneighbors) {
   facetT *facet1, *facet2;
   mergeT *merge;
   boolT wasmerge= True, isreduce;
   void **freelistp;  /* used !qh_NOmem */
   vertexT *vertex;
   mergeType mergetype;
   int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;
 
   trace2((qh ferr, 2010, "qh_all_merges: starting to merge facets beginning from f%d\n",
             getid_(qh newfacet_list)));
   while (True) {
     wasmerge= False;
     while (qh_setsize(qh facet_mergeset)) {
       while ((merge= (mergeT*)qh_setdellast(qh facet_mergeset))) {
         facet1= merge->facet1;
         facet2= merge->facet2;
         mergetype= merge->type;
         qh_memfree_(merge, (int)sizeof(mergeT), freelistp);
         if (facet1->visible || facet2->visible) /*deleted facet*/
           continue;
         if ((facet1->newfacet && !facet1->tested)
                 || (facet2->newfacet && !facet2->tested)) {
           if (qh MERGEindependent && mergetype <= MRGanglecoplanar)
             continue;      /* perform independent sets of merges */
         }
         qh_merge_nonconvex(facet1, facet2, mergetype);
         numdegenredun += qh_merge_degenredundant();
         numnewmerges++;
         wasmerge= True;
         if (mergetype == MRGconcave)
           numconcave++;
         else /* MRGcoplanar or MRGanglecoplanar */
           numcoplanar++;
       } /* while setdellast */
       if (qh POSTmerging && qh hull_dim <= qh_DIMreduceBuild
       && numnewmerges > qh_MAXnewmerges) {
         numnewmerges= 0;
         qh_reducevertices();  /* otherwise large post merges too slow */
       }
       qh_getmergeset(qh newfacet_list); /* facet_mergeset */
     } /* while mergeset */
     if (qh VERTEXneighbors) {
       isreduce= False;
       if (qh hull_dim >=4 && qh POSTmerging) {
         FORALLvertices
           vertex->delridge= True;
         isreduce= True;
       }
       if ((wasmerge || othermerge) && (!qh MERGEexact || qh POSTmerging)
           && qh hull_dim <= qh_DIMreduceBuild) {
         othermerge= False;
         isreduce= True;
       }
       if (isreduce) {
         if (qh_reducevertices()) {
           qh_getmergeset(qh newfacet_list); /* facet_mergeset */
           continue;
         }
       }
     }
     if (vneighbors && qh_test_vneighbors(/* qh.newfacet_list */))
       continue;
     break;
   } /* while (True) */
   if (qh CHECKfrequently && !qh MERGEexact) {
     qh old_randomdist= qh RANDOMdist;
     qh RANDOMdist= False;
     qh_checkconvex(qh newfacet_list, qh_ALGORITHMfault);
     /* qh_checkconnect(); [this is slow and it changes the facet order] */
     qh RANDOMdist= qh old_randomdist;
   }
   trace1((qh ferr, 1009, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",
     numcoplanar, numconcave, numdegenredun));
   if (qh IStracing >= 4 && qh num_facets < 50)
     qh_printlists();
 } /* all_merges */
 
 
 /*---------------------------------
 
   qh_appendmergeset( facet, neighbor, mergetype, angle )
     appends an entry to qh.facet_mergeset or qh.degen_mergeset
 
     angle ignored if NULL or !qh.ANGLEmerge
 
   returns:
     merge appended to facet_mergeset or degen_mergeset
       sets ->degenerate or ->redundant if degen_mergeset
 
   see:
     qh_test_appendmerge()
 
   design:
     allocate merge entry
     if regular merge
       append to qh.facet_mergeset
     else if degenerate merge and qh.facet_mergeset is all degenerate
       append to qh.degen_mergeset
     else if degenerate merge
       prepend to qh.degen_mergeset
     else if redundant merge
       append to qh.degen_mergeset
 */
 void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {
   mergeT *merge, *lastmerge;
   void **freelistp; /* used !qh_NOmem */
 
   if (facet->redundant)
     return;
   if (facet->degenerate && mergetype == MRGdegen)
     return;
   qh_memalloc_((int)sizeof(mergeT), freelistp, merge, mergeT);
   merge->facet1= facet;
   merge->facet2= neighbor;
   merge->type= mergetype;
   if (angle && qh ANGLEmerge)
     merge->angle= *angle;
   if (mergetype < MRGdegen)
     qh_setappend(&(qh facet_mergeset), merge);
   else if (mergetype == MRGdegen) {
     facet->degenerate= True;
     if (!(lastmerge= (mergeT*)qh_setlast(qh degen_mergeset))
     || lastmerge->type == MRGdegen)
       qh_setappend(&(qh degen_mergeset), merge);
     else
       qh_setaddnth(&(qh degen_mergeset), 0, merge);
   }else if (mergetype == MRGredundant) {
     facet->redundant= True;
     qh_setappend(&(qh degen_mergeset), merge);
   }else /* mergetype == MRGmirror */ {
     if (facet->redundant || neighbor->redundant) {
       qh_fprintf(qh ferr, 6092, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n",
            facet->id, neighbor->id);
       qh_errexit2(qh_ERRqhull, facet, neighbor);
     }
     if (!qh_setequal(facet->vertices, neighbor->vertices)) {
       qh_fprintf(qh ferr, 6093, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
            facet->id, neighbor->id);
       qh_errexit2(qh_ERRqhull, facet, neighbor);
     }
     facet->redundant= True;
     neighbor->redundant= True;
     qh_setappend(&(qh degen_mergeset), merge);
   }
 } /* appendmergeset */
 
 
 /*---------------------------------
 
   qh_basevertices( samecycle )
     return temporary set of base vertices for samecycle
     samecycle is first facet in the cycle
     assumes apex is SETfirst_( samecycle->vertices )
 
   returns:
     vertices(settemp)
     all ->seen are cleared
 
   notes:
     uses qh_vertex_visit;
 
   design:
     for each facet in samecycle
       for each unseen vertex in facet->vertices
         append to result
 */
 setT *qh_basevertices(facetT *samecycle) {
   facetT *same;
   vertexT *apex, *vertex, **vertexp;
   setT *vertices= qh_settemp(qh TEMPsize);
 
   apex= SETfirstt_(samecycle->vertices, vertexT);
   apex->visitid= ++qh vertex_visit;
   FORALLsame_cycle_(samecycle) {
     if (same->mergeridge)
       continue;
     FOREACHvertex_(same->vertices) {
       if (vertex->visitid != qh vertex_visit) {
         qh_setappend(&vertices, vertex);
         vertex->visitid= qh vertex_visit;
         vertex->seen= False;
       }
     }
   }
   trace4((qh ferr, 4019, "qh_basevertices: found %d vertices\n",
          qh_setsize(vertices)));
   return vertices;
 } /* basevertices */
 
 /*---------------------------------
 
   qh_checkconnect()
     check that new facets are connected
     new facets are on qh.newfacet_list
 
   notes:
     this is slow and it changes the order of the facets
     uses qh.visit_id
 
   design:
     move first new facet to end of qh.facet_list
     for all newly appended facets
       append unvisited neighbors to end of qh.facet_list
     for all new facets
       report error if unvisited
 */
 void qh_checkconnect(void /* qh.newfacet_list */) {
   facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
 
   facet= qh newfacet_list;
   qh_removefacet(facet);
   qh_appendfacet(facet);
   facet->visitid= ++qh visit_id;
   FORALLfacet_(facet) {
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh visit_id) {
         qh_removefacet(neighbor);
         qh_appendfacet(neighbor);
         neighbor->visitid= qh visit_id;
       }
     }
   }
   FORALLnew_facets {
     if (newfacet->visitid == qh visit_id)
       break;
     qh_fprintf(qh ferr, 6094, "qhull error: f%d is not attached to the new facets\n",
          newfacet->id);
     errfacet= newfacet;
   }
   if (errfacet)
     qh_errexit(qh_ERRqhull, errfacet, NULL);
 } /* checkconnect */
 
 /*---------------------------------
 
   qh_checkzero( testall )
     check that facets are clearly convex for qh.DISTround with qh.MERGEexact
 
     if testall,
       test all facets for qh.MERGEexact post-merging
     else
       test qh.newfacet_list
 
     if qh.MERGEexact,
       allows coplanar ridges
       skips convexity test while qh.ZEROall_ok
 
   returns:
     True if all facets !flipped, !dupridge, normal
          if all horizon facets are simplicial
          if all vertices are clearly below neighbor
          if all opposite vertices of horizon are below
     clears qh.ZEROall_ok if any problems or coplanar facets
 
   notes:
     uses qh.vertex_visit
     horizon facets may define multiple new facets
 
   design:
     for all facets in qh.newfacet_list or qh.facet_list
       check for flagged faults (flipped, etc.)
     for all facets in qh.newfacet_list or qh.facet_list
       for each neighbor of facet
         skip horizon facets for qh.newfacet_list
         test the opposite vertex
       if qh.newfacet_list
         test the other vertices in the facet's horizon facet
 */
 boolT qh_checkzero(boolT testall) {
   facetT *facet, *neighbor, **neighborp;
   facetT *horizon, *facetlist;
   int neighbor_i;
   vertexT *vertex, **vertexp;
   realT dist;
 
   if (testall)
     facetlist= qh facet_list;
   else {
     facetlist= qh newfacet_list;
     FORALLfacet_(facetlist) {
       horizon= SETfirstt_(facet->neighbors, facetT);
       if (!horizon->simplicial)
         goto LABELproblem;
       if (facet->flipped || facet->dupridge || !facet->normal)
         goto LABELproblem;
     }
     if (qh MERGEexact && qh ZEROall_ok) {
       trace2((qh ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));
       return True;
     }
   }
   FORALLfacet_(facetlist) {
     qh vertex_visit++;
     neighbor_i= 0;
     horizon= NULL;
     FOREACHneighbor_(facet) {
       if (!neighbor_i && !testall) {
         horizon= neighbor;
         neighbor_i++;
         continue; /* horizon facet tested in qh_findhorizon */
       }
       vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
       vertex->visitid= qh vertex_visit;
       zzinc_(Zdistzero);
       qh_distplane(vertex->point, neighbor, &dist);
       if (dist >= -qh DISTround) {
         qh ZEROall_ok= False;
         if (!qh MERGEexact || testall || dist > qh DISTround)
           goto LABELnonconvex;
       }
     }
     if (!testall) {
       FOREACHvertex_(horizon->vertices) {
         if (vertex->visitid != qh vertex_visit) {
           zzinc_(Zdistzero);
           qh_distplane(vertex->point, facet, &dist);
           if (dist >= -qh DISTround) {
             qh ZEROall_ok= False;
             if (!qh MERGEexact || dist > qh DISTround)
               goto LABELnonconvex;
           }
           break;
         }
       }
     }
   }
   trace2((qh ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,
         (qh MERGEexact && !testall) ?
            "not concave, flipped, or duplicate ridged" : "clearly convex"));
   return True;
 
  LABELproblem:
   qh ZEROall_ok= False;
   trace2((qh ferr, 2013, "qh_checkzero: facet f%d needs pre-merging\n",
        facet->id));
   return False;
 
  LABELnonconvex:
   trace2((qh ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
          facet->id, neighbor->id, vertex->id, dist));
   return False;
 } /* checkzero */
 
 /*---------------------------------
 
   qh_compareangle( angle1, angle2 )
     used by qsort() to order merges by angle
 */
 int qh_compareangle(const void *p1, const void *p2) {
   const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
 
   return((a->angle > b->angle) ? 1 : -1);
 } /* compareangle */
 
 /*---------------------------------
 
   qh_comparemerge( merge1, merge2 )
     used by qsort() to order merges
 */
 int qh_comparemerge(const void *p1, const void *p2) {
   const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
 
   return(a->type - b->type);
 } /* comparemerge */
 
 /*---------------------------------
 
   qh_comparevisit( vertex1, vertex2 )
     used by qsort() to order vertices by their visitid
 */
 int qh_comparevisit(const void *p1, const void *p2) {
   const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);
 
   return(a->visitid - b->visitid);
 } /* comparevisit */
 
 /*---------------------------------
 
   qh_copynonconvex( atridge )
     set non-convex flag on other ridges (if any) between same neighbors
 
   notes:
     may be faster if use smaller ridge set
 
   design:
     for each ridge of atridge's top facet
       if ridge shares the same neighbor
         set nonconvex flag
 */
 void qh_copynonconvex(ridgeT *atridge) {
   facetT *facet, *otherfacet;
   ridgeT *ridge, **ridgep;
 
   facet= atridge->top;
   otherfacet= atridge->bottom;
   FOREACHridge_(facet->ridges) {
     if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {
       ridge->nonconvex= True;
       trace4((qh ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",
               atridge->id, ridge->id));
       break;
     }
   }
 } /* copynonconvex */
 
 /*---------------------------------
 
   qh_degen_redundant_facet( facet )
     check facet for degen. or redundancy
 
   notes:
     bumps vertex_visit
     called if a facet was redundant but no longer is (qh_merge_degenredundant)
     qh_appendmergeset() only appends first reference to facet (i.e., redundant)
 
   see:
     qh_degen_redundant_neighbors()
 
   design:
     test for redundant neighbor
     test for degenerate facet
 */
 void qh_degen_redundant_facet(facetT *facet) {
   vertexT *vertex, **vertexp;
   facetT *neighbor, **neighborp;
 
   trace4((qh ferr, 4021, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
           facet->id));
   FOREACHneighbor_(facet) {
     qh vertex_visit++;
     FOREACHvertex_(neighbor->vertices)
       vertex->visitid= qh vertex_visit;
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh vertex_visit)
         break;
     }
     if (!vertex) {
       qh_appendmergeset(facet, neighbor, MRGredundant, NULL);
       trace2((qh ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id));
       return;
     }
   }
   if (qh_setsize(facet->neighbors) < qh hull_dim) {
     qh_appendmergeset(facet, facet, MRGdegen, NULL);
     trace2((qh ferr, 2016, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
   }
 } /* degen_redundant_facet */
 
 
 /*---------------------------------
 
   qh_degen_redundant_neighbors( facet, delfacet,  )
     append degenerate and redundant neighbors to facet_mergeset
     if delfacet,
       only checks neighbors of both delfacet and facet
     also checks current facet for degeneracy
 
   notes:
     bumps vertex_visit
     called for each qh_mergefacet() and qh_mergecycle()
     merge and statistics occur in merge_nonconvex
     qh_appendmergeset() only appends first reference to facet (i.e., redundant)
       it appends redundant facets after degenerate ones
 
     a degenerate facet has fewer than hull_dim neighbors
     a redundant facet's vertices is a subset of its neighbor's vertices
     tests for redundant merges first (appendmergeset is nop for others)
     in a merge, only needs to test neighbors of merged facet
 
   see:
     qh_merge_degenredundant() and qh_degen_redundant_facet()
 
   design:
     test for degenerate facet
     test for redundant neighbor
     test for degenerate neighbor
 */
 void qh_degen_redundant_neighbors(facetT *facet, facetT *delfacet) {
   vertexT *vertex, **vertexp;
   facetT *neighbor, **neighborp;
   int size;
 
   trace4((qh ferr, 4022, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n",
           facet->id, getid_(delfacet)));
   if ((size= qh_setsize(facet->neighbors)) < qh hull_dim) {
     qh_appendmergeset(facet, facet, MRGdegen, NULL);
     trace2((qh ferr, 2017, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
   }
   if (!delfacet)
     delfacet= facet;
   qh vertex_visit++;
   FOREACHvertex_(facet->vertices)
     vertex->visitid= qh vertex_visit;
   FOREACHneighbor_(delfacet) {
     /* uses early out instead of checking vertex count */
     if (neighbor == facet)
       continue;
     FOREACHvertex_(neighbor->vertices) {
       if (vertex->visitid != qh vertex_visit)
         break;
     }
     if (!vertex) {
       qh_appendmergeset(neighbor, facet, MRGredundant, NULL);
       trace2((qh ferr, 2018, "qh_degen_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id));
     }
   }
   FOREACHneighbor_(delfacet) {   /* redundant merges occur first */
     if (neighbor == facet)
       continue;
     if ((size= qh_setsize(neighbor->neighbors)) < qh hull_dim) {
       qh_appendmergeset(neighbor, neighbor, MRGdegen, NULL);
       trace2((qh ferr, 2019, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id));
     }
   }
 } /* degen_redundant_neighbors */
 
 
 /*---------------------------------
 
   qh_find_newvertex( oldvertex, vertices, ridges )
     locate new vertex for renaming old vertex
     vertices is a set of possible new vertices
       vertices sorted by number of deleted ridges
 
   returns:
     newvertex or NULL
       each ridge includes both vertex and oldvertex
     vertices sorted by number of deleted ridges
 
   notes:
     modifies vertex->visitid
     new vertex is in one of the ridges
     renaming will not cause a duplicate ridge
     renaming will minimize the number of deleted ridges
     newvertex may not be adjacent in the dual (though unlikely)
 
   design:
     for each vertex in vertices
       set vertex->visitid to number of references in ridges
     remove unvisited vertices
     set qh.vertex_visit above all possible values
     sort vertices by number of references in ridges
     add each ridge to qh.hash_table
     for each vertex in vertices
       look for a vertex that would not cause a duplicate ridge after a rename
 */
 vertexT *qh_find_newvertex(vertexT *oldvertex, setT *vertices, setT *ridges) {
   vertexT *vertex, **vertexp;
   setT *newridges;
   ridgeT *ridge, **ridgep;
   int size, hashsize;
   int hash;
 
 #ifndef qh_NOtrace
   if (qh IStracing >= 4) {
     qh_fprintf(qh ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",
              oldvertex->id);
     FOREACHvertex_(vertices)
       qh_fprintf(qh ferr, 8064, "v%d ", vertex->id);
     FOREACHridge_(ridges)
       qh_fprintf(qh ferr, 8065, "r%d ", ridge->id);
     qh_fprintf(qh ferr, 8066, "\n");
   }
 #endif
   FOREACHvertex_(vertices)
     vertex->visitid= 0;
   FOREACHridge_(ridges) {
     FOREACHvertex_(ridge->vertices)
       vertex->visitid++;
   }
   FOREACHvertex_(vertices) {
     if (!vertex->visitid) {
       qh_setdelnth(vertices, SETindex_(vertices,vertex));
       vertexp--; /* repeat since deleted this vertex */
     }
   }
   qh vertex_visit += (unsigned int)qh_setsize(ridges);
   if (!qh_setsize(vertices)) {
     trace4((qh ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",
             oldvertex->id));
     return NULL;
   }
   qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(vertices),
                 sizeof(vertexT *), qh_comparevisit);
   /* can now use qh vertex_visit */
   if (qh PRINTstatistics) {
     size= qh_setsize(vertices);
     zinc_(Zintersect);
     zadd_(Zintersecttot, size);
     zmax_(Zintersectmax, size);
   }
   hashsize= qh_newhashtable(qh_setsize(ridges));
   FOREACHridge_(ridges)
     qh_hashridge(qh hash_table, hashsize, ridge, oldvertex);
   FOREACHvertex_(vertices) {
     newridges= qh_vertexridges(vertex);
     FOREACHridge_(newridges) {
       if (qh_hashridge_find(qh hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
         zinc_(Zdupridge);
         break;
       }
     }
     qh_settempfree(&newridges);
     if (!ridge)
       break;  /* found a rename */
   }
   if (vertex) {
     /* counted in qh_renamevertex */
     trace2((qh ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
       vertex->id, oldvertex->id, qh_setsize(vertices), qh_setsize(ridges)));
   }else {
     zinc_(Zfindfail);
     trace0((qh ferr, 14, "qh_find_newvertex: no vertex for renaming v%d(all duplicated ridges) during p%d\n",
       oldvertex->id, qh furthest_id));
   }
   qh_setfree(&qh hash_table);
   return vertex;
 } /* find_newvertex */
 
 /*---------------------------------
 
   qh_findbest_test( testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )
     test neighbor of facet for qh_findbestneighbor()
     if testcentrum,
       tests centrum (assumes it is defined)
     else
       tests vertices
 
   returns:
     if a better facet (i.e., vertices/centrum of facet closer to neighbor)
       updates bestfacet, dist, mindist, and maxdist
 */
 void qh_findbest_test(boolT testcentrum, facetT *facet, facetT *neighbor,
       facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
   realT dist, mindist, maxdist;
 
   if (testcentrum) {
     zzinc_(Zbestdist);
     qh_distplane(facet->center, neighbor, &dist);
     dist *= qh hull_dim; /* estimate furthest vertex */
     if (dist < 0) {
       maxdist= 0;
       mindist= dist;
       dist= -dist;
     }else {
       mindist= 0;
       maxdist= dist;
     }
   }else
     dist= qh_getdistance(facet, neighbor, &mindist, &maxdist);
   if (dist < *distp) {
     *bestfacet= neighbor;
     *mindistp= mindist;
     *maxdistp= maxdist;
     *distp= dist;
   }
 } /* findbest_test */
 
 /*---------------------------------
 
   qh_findbestneighbor( facet, dist, mindist, maxdist )
     finds best neighbor (least dist) of a facet for merging
 
   returns:
     returns min and max distances and their max absolute value
 
   notes:
     avoids merging old into new
     assumes ridge->nonconvex only set on one ridge between a pair of facets
     could use an early out predicate but not worth it
 
   design:
     if a large facet
       will test centrum
     else
       will test vertices
     if a large facet
       test nonconvex neighbors for best merge
     else
       test all neighbors for the best merge
     if testing centrum
       get distance information
 */
 facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
   facetT *neighbor, **neighborp, *bestfacet= NULL;
   ridgeT *ridge, **ridgep;
   boolT nonconvex= True, testcentrum= False;
   int size= qh_setsize(facet->vertices);
 
   *distp= REALmax;
   if (size > qh_BESTcentrum2 * qh hull_dim + qh_BESTcentrum) {
     testcentrum= True;
     zinc_(Zbestcentrum);
     if (!facet->center)
        facet->center= qh_getcentrum(facet);
   }
   if (size > qh hull_dim + qh_BESTnonconvex) {
     FOREACHridge_(facet->ridges) {
       if (ridge->nonconvex) {
         neighbor= otherfacet_(ridge, facet);
         qh_findbest_test(testcentrum, facet, neighbor,
                           &bestfacet, distp, mindistp, maxdistp);
       }
     }
   }
   if (!bestfacet) {
     nonconvex= False;
     FOREACHneighbor_(facet)
       qh_findbest_test(testcentrum, facet, neighbor,
                         &bestfacet, distp, mindistp, maxdistp);
   }
   if (!bestfacet) {
     qh_fprintf(qh ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
 
     qh_errexit(qh_ERRqhull, facet, NULL);
   }
   if (testcentrum)
     qh_getdistance(facet, bestfacet, mindistp, maxdistp);
   trace3((qh ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
      bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
   return(bestfacet);
 } /* findbestneighbor */
 
 
 /*---------------------------------
 
   qh_flippedmerges( facetlist, wasmerge )
     merge flipped facets into best neighbor
     assumes qh.facet_mergeset at top of temporary stack
 
   returns:
     no flipped facets on facetlist
     sets wasmerge if merge occurred
     degen/redundant merges passed through
 
   notes:
     othermerges not needed since qh.facet_mergeset is empty before & after
       keep it in case of change
 
   design:
     append flipped facets to qh.facetmergeset
     for each flipped merge
       find best neighbor
       merge facet into neighbor
       merge degenerate and redundant facets
     remove flipped merges from qh.facet_mergeset
 */
 void qh_flippedmerges(facetT *facetlist, boolT *wasmerge) {
   facetT *facet, *neighbor, *facet1;
   realT dist, mindist, maxdist;
   mergeT *merge, **mergep;
   setT *othermerges;
   int nummerge=0;
 
   trace4((qh ferr, 4024, "qh_flippedmerges: begin\n"));
   FORALLfacet_(facetlist) {
     if (facet->flipped && !facet->visible)
       qh_appendmergeset(facet, facet, MRGflip, NULL);
   }
   othermerges= qh_settemppop(); /* was facet_mergeset */
   qh facet_mergeset= qh_settemp(qh TEMPsize);
   qh_settemppush(othermerges);
   FOREACHmerge_(othermerges) {
     facet1= merge->facet1;
     if (merge->type != MRGflip || facet1->visible)
       continue;
     if (qh TRACEmerge-1 == zzval_(Ztotmerge))
       qhmem.IStracing= qh IStracing= qh TRACElevel;
     neighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
     trace0((qh ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
       facet1->id, neighbor->id, dist, qh furthest_id));
     qh_mergefacet(facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);
     nummerge++;
     if (qh PRINTstatistics) {
       zinc_(Zflipped);
       wadd_(Wflippedtot, dist);
       wmax_(Wflippedmax, dist);
     }
     qh_merge_degenredundant();
   }
   FOREACHmerge_(othermerges) {
     if (merge->facet1->visible || merge->facet2->visible)
       qh_memfree(merge, (int)sizeof(mergeT));
     else
       qh_setappend(&qh facet_mergeset, merge);
   }
   qh_settempfree(&othermerges);
   if (nummerge)
     *wasmerge= True;
   trace1((qh ferr, 1010, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
 } /* flippedmerges */
 
 
 /*---------------------------------
 
   qh_forcedmerges( wasmerge )
     merge duplicated ridges
 
   returns:
     removes all duplicate ridges on facet_mergeset
     wasmerge set if merge
     qh.facet_mergeset may include non-forced merges(none for now)
     qh.degen_mergeset includes degen/redun merges
 
   notes:
     duplicate ridges occur when the horizon is pinched,
         i.e. a subridge occurs in more than two horizon ridges.
      could rename vertices that pinch the horizon
     assumes qh_merge_degenredundant() has not be called
     othermerges isn't needed since facet_mergeset is empty afterwards
       keep it in case of change
 
   design:
     for each duplicate ridge
       find current facets by chasing f.replace links
       determine best direction for facet
       merge one facet into the other
       remove duplicate ridges from qh.facet_mergeset
 */
 void qh_forcedmerges(boolT *wasmerge) {
   facetT *facet1, *facet2;
   mergeT *merge, **mergep;
   realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;
   setT *othermerges;
   int nummerge=0, numflip=0;
 
   if (qh TRACEmerge-1 == zzval_(Ztotmerge))
     qhmem.IStracing= qh IStracing= qh TRACElevel;
   trace4((qh ferr, 4025, "qh_forcedmerges: begin\n"));
   othermerges= qh_settemppop(); /* was facet_mergeset */
   qh facet_mergeset= qh_settemp(qh TEMPsize);
   qh_settemppush(othermerges);
   FOREACHmerge_(othermerges) {
     if (merge->type != MRGridge)
         continue;
     facet1= merge->facet1;
     facet2= merge->facet2;
     while (facet1->visible)      /* must exist, no qh_merge_degenredunant */
       facet1= facet1->f.replace; /* previously merged facet */
     while (facet2->visible)
       facet2= facet2->f.replace; /* previously merged facet */
     if (facet1 == facet2)
       continue;
     if (!qh_setin(facet2->neighbors, facet1)) {
       qh_fprintf(qh ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",
                merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
       qh_errexit2(qh_ERRqhull, facet1, facet2);
     }
     if (qh TRACEmerge-1 == zzval_(Ztotmerge))
       qhmem.IStracing= qh IStracing= qh TRACElevel;
     dist1= qh_getdistance(facet1, facet2, &mindist1, &maxdist1);
     dist2= qh_getdistance(facet2, facet1, &mindist2, &maxdist2);
     trace0((qh ferr, 16, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g during p%d\n",
             facet1->id, facet2->id, dist1, dist2, qh furthest_id));
     if (dist1 < dist2)
       qh_mergefacet(facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);
     else {
       qh_mergefacet(facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);
       dist1= dist2;
       facet1= facet2;
     }
     if (facet1->flipped) {
       zinc_(Zmergeflipdup);
       numflip++;
     }else
       nummerge++;
     if (qh PRINTstatistics) {
       zinc_(Zduplicate);
       wadd_(Wduplicatetot, dist1);
       wmax_(Wduplicatemax, dist1);
     }
   }
   FOREACHmerge_(othermerges) {
     if (merge->type == MRGridge)
       qh_memfree(merge, (int)sizeof(mergeT));
     else
       qh_setappend(&qh facet_mergeset, merge);
   }
   qh_settempfree(&othermerges);
   if (nummerge)
     *wasmerge= True;
   trace1((qh ferr, 1011, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n",
                 nummerge, numflip));
 } /* forcedmerges */
 
 
 /*---------------------------------
 
   qh_getmergeset( facetlist )
     determines nonconvex facets on facetlist
     tests !tested ridges and nonconvex ridges of !tested facets
 
   returns:
     returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
     all ridges tested
 
   notes:
     assumes no nonconvex ridges with both facets tested
     uses facet->tested/ridge->tested to prevent duplicate tests
     can not limit tests to modified ridges since the centrum changed
     uses qh.visit_id
 
   see:
     qh_getmergeset_initial()
 
   design:
     for each facet on facetlist
       for each ridge of facet
         if untested ridge
           test ridge for convexity
           if non-convex
             append ridge to qh.facet_mergeset
     sort qh.facet_mergeset by angle
 */
 void qh_getmergeset(facetT *facetlist) {
   facetT *facet, *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int nummerges;
 
   nummerges= qh_setsize(qh facet_mergeset);
   trace4((qh ferr, 4026, "qh_getmergeset: started.\n"));
   qh visit_id++;
   FORALLfacet_(facetlist) {
     if (facet->tested)
       continue;
     facet->visitid= qh visit_id;
     facet->tested= True;  /* must be non-simplicial due to merge */
     FOREACHneighbor_(facet)
       neighbor->seen= False;
     FOREACHridge_(facet->ridges) {
       if (ridge->tested && !ridge->nonconvex)
         continue;
       /* if tested & nonconvex, need to append merge */
       neighbor= otherfacet_(ridge, facet);
       if (neighbor->seen) {
         ridge->tested= True;
         ridge->nonconvex= False;
       }else if (neighbor->visitid != qh visit_id) {
         ridge->tested= True;
         ridge->nonconvex= False;
         neighbor->seen= True;      /* only one ridge is marked nonconvex */
         if (qh_test_appendmerge(facet, neighbor))
           ridge->nonconvex= True;
       }
     }
   }
   nummerges= qh_setsize(qh facet_mergeset);
   if (qh ANGLEmerge)
     qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);
   else
     qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);
   if (qh POSTmerging) {
     zadd_(Zmergesettot2, nummerges);
   }else {
     zadd_(Zmergesettot, nummerges);
     zmax_(Zmergesetmax, nummerges);
   }
   trace2((qh ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));
 } /* getmergeset */
 
 
 /*---------------------------------
 
   qh_getmergeset_initial( facetlist )
     determine initial qh.facet_mergeset for facets
     tests all facet/neighbor pairs on facetlist
 
   returns:
     sorted qh.facet_mergeset with nonconvex ridges
     sets facet->tested, ridge->tested, and ridge->nonconvex
 
   notes:
     uses visit_id, assumes ridge->nonconvex is False
 
   see:
     qh_getmergeset()
 
   design:
     for each facet on facetlist
       for each untested neighbor of facet
         test facet and neighbor for convexity
         if non-convex
           append merge to qh.facet_mergeset
           mark one of the ridges as nonconvex
     sort qh.facet_mergeset by angle
 */
 void qh_getmergeset_initial(facetT *facetlist) {
   facetT *facet, *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int nummerges;
 
   qh visit_id++;
   FORALLfacet_(facetlist) {
     facet->visitid= qh visit_id;
     facet->tested= True;
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh visit_id) {
         if (qh_test_appendmerge(facet, neighbor)) {
           FOREACHridge_(neighbor->ridges) {
             if (facet == otherfacet_(ridge, neighbor)) {
               ridge->nonconvex= True;
               break;    /* only one ridge is marked nonconvex */
             }
           }
         }
       }
     }
     FOREACHridge_(facet->ridges)
       ridge->tested= True;
   }
   nummerges= qh_setsize(qh facet_mergeset);
   if (qh ANGLEmerge)
     qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);
   else
     qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);
   if (qh POSTmerging) {
     zadd_(Zmergeinittot2, nummerges);
   }else {
     zadd_(Zmergeinittot, nummerges);
     zmax_(Zmergeinitmax, nummerges);
   }
   trace2((qh ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));
 } /* getmergeset_initial */
 
 
 /*---------------------------------
 
   qh_hashridge( hashtable, hashsize, ridge, oldvertex )
     add ridge to hashtable without oldvertex
 
   notes:
     assumes hashtable is large enough
 
   design:
     determine hash value for ridge without oldvertex
     find next empty slot for ridge
 */
 void qh_hashridge(setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
   int hash;
   ridgeT *ridgeA;
 
   hash= qh_gethash(hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex);
   while (True) {
     if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
       SETelem_(hashtable, hash)= ridge;
       break;
     }else if (ridgeA == ridge)
       break;
     if (++hash == hashsize)
       hash= 0;
   }
 } /* hashridge */
 
 
 /*---------------------------------
 
   qh_hashridge_find( hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
     returns matching ridge without oldvertex in hashtable
       for ridge without vertex
     if oldvertex is NULL
       matches with any one skip
 
   returns:
     matching ridge or NULL
     if no match,
       if ridge already in   table
         hashslot= -1
       else
         hashslot= next NULL index
 
   notes:
     assumes hashtable is large enough
     can't match ridge to itself
 
   design:
     get hash value for ridge without vertex
     for each hashslot
       return match if ridge matches ridgeA without oldvertex
 */
 ridgeT *qh_hashridge_find(setT *hashtable, int hashsize, ridgeT *ridge,
               vertexT *vertex, vertexT *oldvertex, int *hashslot) {
   int hash;
   ridgeT *ridgeA;
 
   *hashslot= 0;
   zinc_(Zhashridge);
   hash= qh_gethash(hashsize, ridge->vertices, qh hull_dim-1, 0, vertex);
   while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
     if (ridgeA == ridge)
       *hashslot= -1;
     else {
       zinc_(Zhashridgetest);
       if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))
         return ridgeA;
     }
     if (++hash == hashsize)
       hash= 0;
   }
   if (!*hashslot)
     *hashslot= hash;
   return NULL;
 } /* hashridge_find */
 
 
 /*---------------------------------
 
   qh_makeridges( facet )
     creates explicit ridges between simplicial facets
 
   returns:
     facet with ridges and without qh_MERGEridge
     ->simplicial is False
 
   notes:
     allows qh_MERGEridge flag
     uses existing ridges
     duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
 
   see:
     qh_mergecycle_ridges()
 
   design:
     look for qh_MERGEridge neighbors
     mark neighbors that already have ridges
     for each unprocessed neighbor of facet
       create a ridge for neighbor and facet
     if any qh_MERGEridge neighbors
       delete qh_MERGEridge flags (already handled by qh_mark_dupridges)
 */
 void qh_makeridges(facetT *facet) {
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int neighbor_i, neighbor_n;
   boolT toporient, mergeridge= False;
 
   if (!facet->simplicial)
     return;
   trace4((qh ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));
   facet->simplicial= False;
   FOREACHneighbor_(facet) {
     if (neighbor == qh_MERGEridge)
       mergeridge= True;
     else
       neighbor->seen= False;
   }
   FOREACHridge_(facet->ridges)
     otherfacet_(ridge, facet)->seen= True;
   FOREACHneighbor_i_(facet) {
     if (neighbor == qh_MERGEridge)
       continue;  /* fixed by qh_mark_dupridges */
     else if (!neighbor->seen) {  /* no current ridges */
       ridge= qh_newridge();
       ridge->vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim,
                                                           neighbor_i, 0);
       toporient= facet->toporient ^ (neighbor_i & 0x1);
       if (toporient) {
         ridge->top= facet;
         ridge->bottom= neighbor;
       }else {
         ridge->top= neighbor;
         ridge->bottom= facet;
       }
 #if 0 /* this also works */
       flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
       if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
         ridge->top= neighbor;
         ridge->bottom= facet;
       }else {
         ridge->top= facet;
         ridge->bottom= neighbor;
       }
 #endif
       qh_setappend(&(facet->ridges), ridge);
       qh_setappend(&(neighbor->ridges), ridge);
     }
   }
   if (mergeridge) {
     while (qh_setdel(facet->neighbors, qh_MERGEridge))
       ; /* delete each one */
   }
 } /* makeridges */
 
 
 /*---------------------------------
 
   qh_mark_dupridges( facetlist )
     add duplicated ridges to qh.facet_mergeset
     facet->dupridge is true
 
   returns:
     duplicate ridges on qh.facet_mergeset
     ->mergeridge/->mergeridge2 set
     duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge
     no MERGEridges in neighbor sets
 
   notes:
     duplicate ridges occur when the horizon is pinched,
         i.e. a subridge occurs in more than two horizon ridges.
     could rename vertices that pinch the horizon
     uses qh.visit_id
 
   design:
     for all facets on facetlist
       if facet contains a duplicate ridge
         for each neighbor of facet
           if neighbor marked qh_MERGEridge (one side of the merge)
             set facet->mergeridge
           else
             if neighbor contains a duplicate ridge
             and the back link is qh_MERGEridge
               append duplicate ridge to qh.facet_mergeset
    for each duplicate ridge
      make ridge sets in preparation for merging
      remove qh_MERGEridge from neighbor set
    for each duplicate ridge
      restore the missing neighbor from the neighbor set that was qh_MERGEridge
      add the missing ridge for this neighbor
 */
 void qh_mark_dupridges(facetT *facetlist) {
   facetT *facet, *neighbor, **neighborp;
   int nummerge=0;
   mergeT *merge, **mergep;
 
 
   trace4((qh ferr, 4028, "qh_mark_dupridges: identify duplicate ridges\n"));
   FORALLfacet_(facetlist) {
     if (facet->dupridge) {
       FOREACHneighbor_(facet) {
         if (neighbor == qh_MERGEridge) {
           facet->mergeridge= True;
           continue;
         }
         if (neighbor->dupridge
         && !qh_setin(neighbor->neighbors, facet)) { /* qh_MERGEridge */
           qh_appendmergeset(facet, neighbor, MRGridge, NULL);
           facet->mergeridge2= True;
           facet->mergeridge= True;
           nummerge++;
         }
       }
     }
   }
   if (!nummerge)
     return;
   FORALLfacet_(facetlist) {            /* gets rid of qh_MERGEridge */
     if (facet->mergeridge && !facet->mergeridge2)
       qh_makeridges(facet);
   }
   FOREACHmerge_(qh facet_mergeset) {   /* restore the missing neighbors */
     if (merge->type == MRGridge) {
       qh_setappend(&merge->facet2->neighbors, merge->facet1);
       qh_makeridges(merge->facet1);   /* and the missing ridges */
     }
   }
   trace1((qh ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges\n",
                 nummerge));
 } /* mark_dupridges */
 
 /*---------------------------------
 
   qh_maydropneighbor( facet )
     drop neighbor relationship if no ridge between facet and neighbor
 
   returns:
     neighbor sets updated
     appends degenerate facets to qh.facet_mergeset
 
   notes:
     won't cause redundant facets since vertex inclusion is the same
     may drop vertex and neighbor if no ridge
     uses qh.visit_id
 
   design:
     visit all neighbors with ridges
     for each unvisited neighbor of facet
       delete neighbor and facet from the neighbor sets
       if neighbor becomes degenerate
         append neighbor to qh.degen_mergeset
     if facet is degenerate
       append facet to qh.degen_mergeset
 */
 void qh_maydropneighbor(facetT *facet) {
   ridgeT *ridge, **ridgep;
   realT angledegen= qh_ANGLEdegen;
   facetT *neighbor, **neighborp;
 
   qh visit_id++;
   trace4((qh ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
           facet->id));
   FOREACHridge_(facet->ridges) {
     ridge->top->visitid= qh visit_id;
     ridge->bottom->visitid= qh visit_id;
   }
   FOREACHneighbor_(facet) {
     if (neighbor->visitid != qh visit_id) {
       trace0((qh ferr, 17, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",
             facet->id, neighbor->id, qh furthest_id));
       zinc_(Zdropneighbor);
       qh_setdel(facet->neighbors, neighbor);
       neighborp--;  /* repeat, deleted a neighbor */
       qh_setdel(neighbor->neighbors, facet);
       if (qh_setsize(neighbor->neighbors) < qh hull_dim) {
         zinc_(Zdropdegen);
         qh_appendmergeset(neighbor, neighbor, MRGdegen, &angledegen);
         trace2((qh ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
       }
     }
   }
   if (qh_setsize(facet->neighbors) < qh hull_dim) {
     zinc_(Zdropdegen);
     qh_appendmergeset(facet, facet, MRGdegen, &angledegen);
     trace2((qh ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
   }
 } /* maydropneighbor */
 
 
 /*---------------------------------
 
   qh_merge_degenredundant()
     merge all degenerate and redundant facets
     qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()
 
   returns:
     number of merges performed
     resets facet->degenerate/redundant
     if deleted (visible) facet has no neighbors
       sets ->f.replace to NULL
 
   notes:
     redundant merges happen before degenerate ones
     merging and renaming vertices can result in degen/redundant facets
 
   design:
     for each merge on qh.degen_mergeset
       if redundant merge
         if non-redundant facet merged into redundant facet
           recheck facet for redundancy
         else
           merge redundant facet into other facet
 */
 int qh_merge_degenredundant(void) {
   int size;
   mergeT *merge;
   facetT *bestneighbor, *facet1, *facet2;
   realT dist, mindist, maxdist;
   vertexT *vertex, **vertexp;
   int nummerges= 0;
   mergeType mergetype;
 
   while ((merge= (mergeT*)qh_setdellast(qh degen_mergeset))) {
     facet1= merge->facet1;
     facet2= merge->facet2;
     mergetype= merge->type;
     qh_memfree(merge, (int)sizeof(mergeT));
     if (facet1->visible)
       continue;
     facet1->degenerate= False;
     facet1->redundant= False;
     if (qh TRACEmerge-1 == zzval_(Ztotmerge))
       qhmem.IStracing= qh IStracing= qh TRACElevel;
     if (mergetype == MRGredundant) {
       zinc_(Zneighbor);
       while (facet2->visible) {
         if (!facet2->f.replace) {
           qh_fprintf(qh ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",
                facet1->id, facet2->id);
           qh_errexit2(qh_ERRqhull, facet1, facet2);
         }
         facet2= facet2->f.replace;
       }
       if (facet1 == facet2) {
         qh_degen_redundant_facet(facet1); /* in case of others */
         continue;
       }
       trace2((qh ferr, 2025, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",
             facet1->id, facet2->id));
       qh_mergefacet(facet1, facet2, NULL, NULL, !qh_MERGEapex);
       /* merge distance is already accounted for */
       nummerges++;
     }else {  /* mergetype == MRGdegen, other merges may have fixed */
       if (!(size= qh_setsize(facet1->neighbors))) {
         zinc_(Zdelfacetdup);
         trace2((qh ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
         qh_willdelete(facet1, NULL);
         FOREACHvertex_(facet1->vertices) {
           qh_setdel(vertex->neighbors, facet1);
           if (!SETfirst_(vertex->neighbors)) {
             zinc_(Zdegenvertex);
             trace2((qh ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
                  vertex->id, facet1->id));
             vertex->deleted= True;
             qh_setappend(&qh del_vertices, vertex);
           }
         }
         nummerges++;
       }else if (size < qh hull_dim) {
         bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
         trace2((qh ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
               facet1->id, size, bestneighbor->id, dist));
         qh_mergefacet(facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
         nummerges++;
         if (qh PRINTstatistics) {
           zinc_(Zdegen);
           wadd_(Wdegentot, dist);
           wmax_(Wdegenmax, dist);
         }
       } /* else, another merge fixed the degeneracy and redundancy tested */
     }
   }
   return nummerges;
 } /* merge_degenredundant */
 
 /*---------------------------------
 
   qh_merge_nonconvex( facet1, facet2, mergetype )
     remove non-convex ridge between facet1 into facet2
     mergetype gives why the facet's are non-convex
 
   returns:
     merges one of the facets into the best neighbor
 
   design:
     if one of the facets is a new facet
       prefer merging new facet into old facet
     find best neighbors for both facets
     merge the nearest facet into its best neighbor
     update the statistics
 */
 void qh_merge_nonconvex(facetT *facet1, facetT *facet2, mergeType mergetype) {
   facetT *bestfacet, *bestneighbor, *neighbor;
   realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
 
   if (qh TRACEmerge-1 == zzval_(Ztotmerge))
     qhmem.IStracing= qh IStracing= qh TRACElevel;
   trace3((qh ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
       zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
   /* concave or coplanar */
   if (!facet1->newfacet) {
     bestfacet= facet2;   /* avoid merging old facet if new is ok */
     facet2= facet1;
     facet1= bestfacet;
   }else
     bestfacet= facet1;
   bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist);
   neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
   if (dist < dist2) {
     qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
   }else if (qh AVOIDold && !facet2->newfacet
   && ((mindist >= -qh MAXcoplanar && maxdist <= qh max_outside)
        || dist * 1.5 < dist2)) {
     zinc_(Zavoidold);
     wadd_(Wavoidoldtot, dist);
     wmax_(Wavoidoldmax, dist);
     trace2((qh ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
            facet2->id, dist2, facet1->id, dist2));
     qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
   }else {
     qh_mergefacet(facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);
     dist= dist2;
   }
   if (qh PRINTstatistics) {
     if (mergetype == MRGanglecoplanar) {
       zinc_(Zacoplanar);
       wadd_(Wacoplanartot, dist);
       wmax_(Wacoplanarmax, dist);
     }else if (mergetype == MRGconcave) {
       zinc_(Zconcave);
       wadd_(Wconcavetot, dist);
       wmax_(Wconcavemax, dist);
     }else { /* MRGcoplanar */
       zinc_(Zcoplanar);
       wadd_(Wcoplanartot, dist);
       wmax_(Wcoplanarmax, dist);
     }
   }
 } /* merge_nonconvex */
 
 /*---------------------------------
 
   qh_mergecycle( samecycle, newfacet )
     merge a cycle of facets starting at samecycle into a newfacet
     newfacet is a horizon facet with ->normal
     samecycle facets are simplicial from an apex
 
   returns:
     initializes vertex neighbors on first merge
     samecycle deleted (placed on qh.visible_list)
     newfacet at end of qh.facet_list
     deleted vertices on qh.del_vertices
 
   see:
     qh_mergefacet()
     called by qh_mergecycle_all() for multiple, same cycle facets
 
   design:
     make vertex neighbors if necessary
     make ridges for newfacet
     merge neighbor sets of samecycle into newfacet
     merge ridges of samecycle into newfacet
     merge vertex neighbors of samecycle into newfacet
     make apex of samecycle the apex of newfacet
     if newfacet wasn't a new facet
       add its vertices to qh.newvertex_list
     delete samecycle facets a make newfacet a newfacet
 */
 void qh_mergecycle(facetT *samecycle, facetT *newfacet) {
   int traceonce= False, tracerestore= 0;
   vertexT *apex;
 #ifndef qh_NOtrace
   facetT *same;
 #endif
 
   if (newfacet->tricoplanar) {
     if (!qh TRInormals) {
       qh_fprintf(qh ferr, 6224, "Qhull internal error (qh_mergecycle): does not work for tricoplanar facets.  Use option 'Q11'\n");
       qh_errexit(qh_ERRqhull, newfacet, NULL);
     }
     newfacet->tricoplanar= False;
     newfacet->keepcentrum= False;
   }
   if (!qh VERTEXneighbors)
     qh_vertexneighbors();
   zzinc_(Ztotmerge);
   if (qh REPORTfreq2 && qh POSTmerging) {
     if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
       qh_tracemerging();
   }
 #ifndef qh_NOtrace
   if (qh TRACEmerge == zzval_(Ztotmerge))
     qhmem.IStracing= qh IStracing= qh TRACElevel;
   trace2((qh ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",
         zzval_(Ztotmerge), samecycle->id, newfacet->id));
   if (newfacet == qh tracefacet) {
     tracerestore= qh IStracing;
     qh IStracing= 4;
     qh_fprintf(qh ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
                zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh furthest_id);
     traceonce= True;
   }
   if (qh IStracing >=4) {
     qh_fprintf(qh ferr, 8069, "  same cycle:");
     FORALLsame_cycle_(samecycle)
       qh_fprintf(qh ferr, 8070, " f%d", same->id);
     qh_fprintf(qh ferr, 8071, "\n");
   }
   if (qh IStracing >=4)
     qh_errprint("MERGING CYCLE", samecycle, newfacet, NULL, NULL);
 #endif /* !qh_NOtrace */
   apex= SETfirstt_(samecycle->vertices, vertexT);
   qh_makeridges(newfacet);
   qh_mergecycle_neighbors(samecycle, newfacet);
   qh_mergecycle_ridges(samecycle, newfacet);
   qh_mergecycle_vneighbors(samecycle, newfacet);
   if (SETfirstt_(newfacet->vertices, vertexT) != apex)
     qh_setaddnth(&newfacet->vertices, 0, apex);  /* apex has last id */
   if (!newfacet->newfacet)
     qh_newvertices(newfacet->vertices);
   qh_mergecycle_facets(samecycle, newfacet);
   qh_tracemerge(samecycle, newfacet);
   /* check for degen_redundant_neighbors after qh_forcedmerges() */
   if (traceonce) {
     qh_fprintf(qh ferr, 8072, "qh_mergecycle: end of trace facet\n");
     qh IStracing= tracerestore;
   }
 } /* mergecycle */
 
 /*---------------------------------
 
   qh_mergecycle_all( facetlist, wasmerge )
     merge all samecycles of coplanar facets into horizon
     don't merge facets with ->mergeridge (these already have ->normal)
     all facets are simplicial from apex
     all facet->cycledone == False
 
   returns:
     all newfacets merged into coplanar horizon facets
     deleted vertices on  qh.del_vertices
     sets wasmerge if any merge
 
   see:
     calls qh_mergecycle for multiple, same cycle facets
 
   design:
     for each facet on facetlist
       skip facets with duplicate ridges and normals
       check that facet is in a samecycle (->mergehorizon)
       if facet only member of samecycle
         sets vertex->delridge for all vertices except apex
         merge facet into horizon
       else
         mark all facets in samecycle
         remove facets with duplicate ridges from samecycle
         merge samecycle into horizon (deletes facets from facetlist)
 */
 void qh_mergecycle_all(facetT *facetlist, boolT *wasmerge) {
   facetT *facet, *same, *prev, *horizon;
   facetT *samecycle= NULL, *nextfacet, *nextsame;
   vertexT *apex, *vertex, **vertexp;
   int cycles=0, total=0, facets, nummerge;
 
   trace2((qh ferr, 2031, "qh_mergecycle_all: begin\n"));
   for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
     if (facet->normal)
       continue;
     if (!facet->mergehorizon) {
       qh_fprintf(qh ferr, 6225, "Qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);
       qh_errexit(qh_ERRqhull, facet, NULL);
     }
     horizon= SETfirstt_(facet->neighbors, facetT);
     if (facet->f.samecycle == facet) {
       zinc_(Zonehorizon);
       /* merge distance done in qh_findhorizon */
       apex= SETfirstt_(facet->vertices, vertexT);
       FOREACHvertex_(facet->vertices) {
         if (vertex != apex)
           vertex->delridge= True;
       }
       horizon->f.newcycle= NULL;
       qh_mergefacet(facet, horizon, NULL, NULL, qh_MERGEapex);
     }else {
       samecycle= facet;
       facets= 0;
       prev= facet;
       for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
            same= (same == facet ? NULL :nextsame)) { /* ends at facet */
         nextsame= same->f.samecycle;
         if (same->cycledone || same->visible)
           qh_infiniteloop(same);
         same->cycledone= True;
         if (same->normal) {
           prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
           same->f.samecycle= NULL;
         }else {
           prev= same;
           facets++;
         }
       }
       while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
         nextfacet= nextfacet->next;
       horizon->f.newcycle= NULL;
       qh_mergecycle(samecycle, horizon);
       nummerge= horizon->nummerge + facets;
       if (nummerge > qh_MAXnummerge)
         horizon->nummerge= qh_MAXnummerge;
       else
         horizon->nummerge= (short unsigned int)nummerge;
       zzinc_(Zcyclehorizon);
       total += facets;
       zzadd_(Zcyclefacettot, facets);
       zmax_(Zcyclefacetmax, facets);
     }
     cycles++;
   }
   if (cycles)
     *wasmerge= True;
   trace1((qh ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));
 } /* mergecycle_all */
 
 /*---------------------------------
 
   qh_mergecycle_facets( samecycle, newfacet )
     finish merge of samecycle into newfacet
 
   returns:
     samecycle prepended to visible_list for later deletion and partitioning
       each facet->f.replace == newfacet
 
     newfacet moved to end of qh.facet_list
       makes newfacet a newfacet (get's facet1->id if it was old)
       sets newfacet->newmerge
       clears newfacet->center (unless merging into a large facet)
       clears newfacet->tested and ridge->tested for facet1
 
     adds neighboring facets to facet_mergeset if redundant or degenerate
 
   design:
     make newfacet a new facet and set its flags
     move samecycle facets to qh.visible_list for later deletion
     unless newfacet is large
       remove its centrum
 */
 void qh_mergecycle_facets(facetT *samecycle, facetT *newfacet) {
   facetT *same, *next;
 
   trace4((qh ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));
   qh_removefacet(newfacet);  /* append as a newfacet to end of qh facet_list */
   qh_appendfacet(newfacet);
   newfacet->newfacet= True;
   newfacet->simplicial= False;
   newfacet->newmerge= True;
 
   for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
     next= same->f.samecycle;  /* reused by willdelete */
     qh_willdelete(same, newfacet);
   }
   if (newfacet->center
       && qh_setsize(newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) {
     qh_memfree(newfacet->center, qh normal_size);
     newfacet->center= NULL;
   }
   trace3((qh ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
              samecycle->id, newfacet->id));
 } /* mergecycle_facets */
 
 /*---------------------------------
 
   qh_mergecycle_neighbors( samecycle, newfacet )
     add neighbors for samecycle facets to newfacet
 
   returns:
     newfacet with updated neighbors and vice-versa
     newfacet has ridges
     all neighbors of newfacet marked with qh.visit_id
     samecycle facets marked with qh.visit_id-1
     ridges updated for simplicial neighbors of samecycle with a ridge
 
   notes:
     assumes newfacet not in samecycle
     usually, samecycle facets are new, simplicial facets without internal ridges
       not so if horizon facet is coplanar to two different samecycles
 
   see:
     qh_mergeneighbors()
 
   design:
     check samecycle
     delete neighbors from newfacet that are also in samecycle
     for each neighbor of a facet in samecycle
       if neighbor is simplicial
         if first visit
           move the neighbor relation to newfacet
           update facet links for its ridges
         else
           make ridges for neighbor
           remove samecycle reference
       else
         update neighbor sets
 */
 void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet) {
   facetT *same, *neighbor, **neighborp;
   int delneighbors= 0, newneighbors= 0;
   unsigned int samevisitid;
   ridgeT *ridge, **ridgep;
 
   samevisitid= ++qh visit_id;
   FORALLsame_cycle_(samecycle) {
     if (same->visitid == samevisitid || same->visible)
       qh_infiniteloop(samecycle);
     same->visitid= samevisitid;
   }
   newfacet->visitid= ++qh visit_id;
   trace4((qh ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));
   FOREACHneighbor_(newfacet) {
     if (neighbor->visitid == samevisitid) {
       SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
       delneighbors++;
     }else
       neighbor->visitid= qh visit_id;
   }
   qh_setcompact(newfacet->neighbors);
 
   trace4((qh ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));
   FORALLsame_cycle_(samecycle) {
     FOREACHneighbor_(same) {
       if (neighbor->visitid == samevisitid)
         continue;
       if (neighbor->simplicial) {
         if (neighbor->visitid != qh visit_id) {
           qh_setappend(&newfacet->neighbors, neighbor);
           qh_setreplace(neighbor->neighbors, same, newfacet);
           newneighbors++;
           neighbor->visitid= qh visit_id;
           FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
             if (ridge->top == same) {
               ridge->top= newfacet;
               break;
             }else if (ridge->bottom == same) {
               ridge->bottom= newfacet;
               break;
             }
           }
         }else {
           qh_makeridges(neighbor);
           qh_setdel(neighbor->neighbors, same);
           /* same can't be horizon facet for neighbor */
         }
       }else { /* non-simplicial neighbor */
         qh_setdel(neighbor->neighbors, same);
         if (neighbor->visitid != qh visit_id) {
           qh_setappend(&neighbor->neighbors, newfacet);
           qh_setappend(&newfacet->neighbors, neighbor);
           neighbor->visitid= qh visit_id;
           newneighbors++;
         }
       }
     }
   }
   trace2((qh ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
              delneighbors, newneighbors));
 } /* mergecycle_neighbors */
 
 /*---------------------------------
 
   qh_mergecycle_ridges( samecycle, newfacet )
     add ridges/neighbors for facets in samecycle to newfacet
     all new/old neighbors of newfacet marked with qh.visit_id
     facets in samecycle marked with qh.visit_id-1
     newfacet marked with qh.visit_id
 
   returns:
     newfacet has merged ridges
 
   notes:
     ridge already updated for simplicial neighbors of samecycle with a ridge
 
   see:
     qh_mergeridges()
     qh_makeridges()
 
   design:
     remove ridges between newfacet and samecycle
     for each facet in samecycle
       for each ridge in facet
         update facet pointers in ridge
         skip ridges processed in qh_mergecycle_neighors
         free ridges between newfacet and samecycle
         free ridges between facets of samecycle (on 2nd visit)
         append remaining ridges to newfacet
       if simpilicial facet
         for each neighbor of facet
           if simplicial facet
           and not samecycle facet or newfacet
             make ridge between neighbor and newfacet
 */
 void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet) {
   facetT *same, *neighbor= NULL;
   int numold=0, numnew=0;
   int neighbor_i, neighbor_n;
   unsigned int samevisitid;
   ridgeT *ridge, **ridgep;
   boolT toporient;
   void **freelistp; /* used !qh_NOmem */
 
   trace4((qh ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));
   samevisitid= qh visit_id -1;
   FOREACHridge_(newfacet->ridges) {
     neighbor= otherfacet_(ridge, newfacet);
     if (neighbor->visitid == samevisitid)
       SETref_(ridge)= NULL; /* ridge free'd below */
   }
   qh_setcompact(newfacet->ridges);
 
   trace4((qh ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));
   FORALLsame_cycle_(samecycle) {
     FOREACHridge_(same->ridges) {
       if (ridge->top == same) {
         ridge->top= newfacet;
         neighbor= ridge->bottom;
       }else if (ridge->bottom == same) {
         ridge->bottom= newfacet;
         neighbor= ridge->top;
       }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
         qh_setappend(&newfacet->ridges, ridge);
         numold++;  /* already set by qh_mergecycle_neighbors */
         continue;
       }else {
         qh_fprintf(qh ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
         qh_errexit(qh_ERRqhull, NULL, ridge);
       }
       if (neighbor == newfacet) {
         qh_setfree(&(ridge->vertices));
         qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
         numold++;
       }else if (neighbor->visitid == samevisitid) {
         qh_setdel(neighbor->ridges, ridge);
         qh_setfree(&(ridge->vertices));
         qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
         numold++;
       }else {
         qh_setappend(&newfacet->ridges, ridge);
         numold++;
       }
     }
     if (same->ridges)
       qh_settruncate(same->ridges, 0);
     if (!same->simplicial)
       continue;
     FOREACHneighbor_i_(same) {       /* note: !newfact->simplicial */
       if (neighbor->visitid != samevisitid && neighbor->simplicial) {
         ridge= qh_newridge();
         ridge->vertices= qh_setnew_delnthsorted(same->vertices, qh hull_dim,
                                                           neighbor_i, 0);
         toporient= same->toporient ^ (neighbor_i & 0x1);
         if (toporient) {
           ridge->top= newfacet;
           ridge->bottom= neighbor;
         }else {
           ridge->top= neighbor;
           ridge->bottom= newfacet;
         }
         qh_setappend(&(newfacet->ridges), ridge);
         qh_setappend(&(neighbor->ridges), ridge);
         numnew++;
       }
     }
   }
 
   trace2((qh ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
              numold, numnew));
 } /* mergecycle_ridges */
 
 /*---------------------------------
 
   qh_mergecycle_vneighbors( samecycle, newfacet )
     create vertex neighbors for newfacet from vertices of facets in samecycle
     samecycle marked with visitid == qh.visit_id - 1
 
   returns:
     newfacet vertices with updated neighbors
     marks newfacet with qh.visit_id-1
     deletes vertices that are merged away
     sets delridge on all vertices (faster here than in mergecycle_ridges)
 
   see:
     qh_mergevertex_neighbors()
 
   design:
     for each vertex of samecycle facet
       set vertex->delridge
       delete samecycle facets from vertex neighbors
       append newfacet to vertex neighbors
       if vertex only in newfacet
         delete it from newfacet
         add it to qh.del_vertices for later deletion
 */
 void qh_mergecycle_vneighbors(facetT *samecycle, facetT *newfacet) {
   facetT *neighbor, **neighborp;
   unsigned int mergeid;
   vertexT *vertex, **vertexp, *apex;
   setT *vertices;
 
   trace4((qh ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));
   mergeid= qh visit_id - 1;
   newfacet->visitid= mergeid;
   vertices= qh_basevertices(samecycle); /* temp */
   apex= SETfirstt_(samecycle->vertices, vertexT);
   qh_setappend(&vertices, apex);
   FOREACHvertex_(vertices) {
     vertex->delridge= True;
     FOREACHneighbor_(vertex) {
       if (neighbor->visitid == mergeid)
         SETref_(neighbor)= NULL;
     }
     qh_setcompact(vertex->neighbors);
     qh_setappend(&vertex->neighbors, newfacet);
     if (!SETsecond_(vertex->neighbors)) {
       zinc_(Zcyclevertex);
       trace2((qh ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
         vertex->id, samecycle->id, newfacet->id));
       qh_setdelsorted(newfacet->vertices, vertex);
       vertex->deleted= True;
       qh_setappend(&qh del_vertices, vertex);
     }
   }
   qh_settempfree(&vertices);
   trace3((qh ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
              samecycle->id, newfacet->id));
 } /* mergecycle_vneighbors */
 
 /*---------------------------------
 
   qh_mergefacet( facet1, facet2, mindist, maxdist, mergeapex )
     merges facet1 into facet2
     mergeapex==qh_MERGEapex if merging new facet into coplanar horizon
 
   returns:
     qh.max_outside and qh.min_vertex updated
     initializes vertex neighbors on first merge
 
   returns:
     facet2 contains facet1's vertices, neighbors, and ridges
       facet2 moved to end of qh.facet_list
       makes facet2 a newfacet
       sets facet2->newmerge set
       clears facet2->center (unless merging into a large facet)
       clears facet2->tested and ridge->tested for facet1
 
     facet1 prepended to visible_list for later deletion and partitioning
       facet1->f.replace == facet2
 
     adds neighboring facets to facet_mergeset if redundant or degenerate
 
   notes:
     mindist/maxdist may be NULL (only if both NULL)
     traces merge if fmax_(maxdist,-mindist) > TRACEdist
 
   see:
     qh_mergecycle()
 
   design:
     trace merge and check for degenerate simplex
     make ridges for both facets
     update qh.max_outside, qh.max_vertex, qh.min_vertex
     update facet2->maxoutside and keepcentrum
     update facet2->nummerge
     update tested flags for facet2
     if facet1 is simplicial
       merge facet1 into facet2
     else
       merge facet1's neighbors into facet2
       merge facet1's ridges into facet2
       merge facet1's vertices into facet2
       merge facet1's vertex neighbors into facet2
       add facet2's vertices to qh.new_vertexlist
       unless qh_MERGEapex
         test facet2 for degenerate or redundant neighbors
       move facet1 to qh.visible_list for later deletion
       move facet2 to end of qh.newfacet_list
 */
 void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {
   boolT traceonce= False;
   vertexT *vertex, **vertexp;
   int tracerestore=0, nummerge;
 
   if (facet1->tricoplanar || facet2->tricoplanar) {
     if (!qh TRInormals) {
       qh_fprintf(qh ferr, 6226, "Qhull internal error (qh_mergefacet): does not work for tricoplanar facets.  Use option 'Q11'\n");
       qh_errexit2(qh_ERRqhull, facet1, facet2);
     }
     if (facet2->tricoplanar) {
       facet2->tricoplanar= False;
       facet2->keepcentrum= False;
     }
   }
   zzinc_(Ztotmerge);
   if (qh REPORTfreq2 && qh POSTmerging) {
     if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
       qh_tracemerging();
   }
 #ifndef qh_NOtrace
   if (qh build_cnt >= qh RERUN) {
     if (mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist)) {
       tracerestore= 0;
       qh IStracing= qh TRACElevel;
       traceonce= True;
       qh_fprintf(qh ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),
              fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh furthest_id);
     }else if (facet1 == qh tracefacet || facet2 == qh tracefacet) {
       tracerestore= qh IStracing;
       qh IStracing= 4;
       traceonce= True;
       qh_fprintf(qh ferr, 8076, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",
                  zzval_(Ztotmerge), qh tracefacet_id,  qh furthest_id);
     }
   }
   if (qh IStracing >= 2) {
     realT mergemin= -2;
     realT mergemax= -2;
 
     if (mindist) {
       mergemin= *mindist;
       mergemax= *maxdist;
     }
     qh_fprintf(qh ferr, 8077, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n",
     zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);
   }
 #endif /* !qh_NOtrace */
   if (facet1 == facet2 || facet1->visible || facet2->visible) {
     qh_fprintf(qh ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",
              facet1->id, facet2->id);
     qh_errexit2(qh_ERRqhull, facet1, facet2);
   }
   if (qh num_facets - qh num_visible <= qh hull_dim + 1) {
     qh_fprintf(qh ferr, 6227, "\n\
 qhull precision error: Only %d facets remain.  Can not merge another\n\
 pair.  The input is too degenerate or the convexity constraints are\n\
 too strong.\n", qh hull_dim+1);
     if (qh hull_dim >= 5 && !qh MERGEexact)
       qh_fprintf(qh ferr, 8079, "Option 'Qx' may avoid this problem.\n");
     qh_errexit(qh_ERRprec, NULL, NULL);
   }
   if (!qh VERTEXneighbors)
     qh_vertexneighbors();
   qh_makeridges(facet1);
   qh_makeridges(facet2);
   if (qh IStracing >=4)
     qh_errprint("MERGING", facet1, facet2, NULL, NULL);
   if (mindist) {
     maximize_(qh max_outside, *maxdist);
     maximize_(qh max_vertex, *maxdist);
 #if qh_MAXoutside
     maximize_(facet2->maxoutside, *maxdist);
 #endif
     minimize_(qh min_vertex, *mindist);
     if (!facet2->keepcentrum
     && (*maxdist > qh WIDEfacet || *mindist < -qh WIDEfacet)) {
       facet2->keepcentrum= True;
       zinc_(Zwidefacet);
     }
   }
   nummerge= facet1->nummerge + facet2->nummerge + 1;
   if (nummerge >= qh_MAXnummerge)
     facet2->nummerge= qh_MAXnummerge;
   else
     facet2->nummerge= (short unsigned int)nummerge;
   facet2->newmerge= True;
   facet2->dupridge= False;
   qh_updatetested(facet1, facet2);
   if (qh hull_dim > 2 && qh_setsize(facet1->vertices) == qh hull_dim)
     qh_mergesimplex(facet1, facet2, mergeapex);
   else {
     qh vertex_visit++;
     FOREACHvertex_(facet2->vertices)
       vertex->visitid= qh vertex_visit;
     if (qh hull_dim == 2)
       qh_mergefacet2d(facet1, facet2);
     else {
       qh_mergeneighbors(facet1, facet2);
       qh_mergevertices(facet1->vertices, &facet2->vertices);
     }
     qh_mergeridges(facet1, facet2);
     qh_mergevertex_neighbors(facet1, facet2);
     if (!facet2->newfacet)
       qh_newvertices(facet2->vertices);
   }
   if (!mergeapex)
     qh_degen_redundant_neighbors(facet2, facet1);
   if (facet2->coplanar || !facet2->newfacet) {
     zinc_(Zmergeintohorizon);
   }else if (!facet1->newfacet && facet2->newfacet) {
     zinc_(Zmergehorizon);
   }else {
     zinc_(Zmergenew);
   }
   qh_willdelete(facet1, facet2);
   qh_removefacet(facet2);  /* append as a newfacet to end of qh facet_list */
   qh_appendfacet(facet2);
   facet2->newfacet= True;
   facet2->tested= False;
   qh_tracemerge(facet1, facet2);
   if (traceonce) {
     qh_fprintf(qh ferr, 8080, "qh_mergefacet: end of wide tracing\n");
     qh IStracing= tracerestore;
   }
 } /* mergefacet */
 
 
 /*---------------------------------
 
   qh_mergefacet2d( facet1, facet2 )
     in 2d, merges neighbors and vertices of facet1 into facet2
 
   returns:
     build ridges for neighbors if necessary
     facet2 looks like a simplicial facet except for centrum, ridges
       neighbors are opposite the corresponding vertex
       maintains orientation of facet2
 
   notes:
     qh_mergefacet() retains non-simplicial structures
       they are not needed in 2d, but later routines may use them
     preserves qh.vertex_visit for qh_mergevertex_neighbors()
 
   design:
     get vertices and neighbors
     determine new vertices and neighbors
     set new vertices and neighbors and adjust orientation
     make ridges for new neighbor if needed
 */
 void qh_mergefacet2d(facetT *facet1, facetT *facet2) {
   vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
   facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
 
   vertex1A= SETfirstt_(facet1->vertices, vertexT);
   vertex1B= SETsecondt_(facet1->vertices, vertexT);
   vertex2A= SETfirstt_(facet2->vertices, vertexT);
   vertex2B= SETsecondt_(facet2->vertices, vertexT);
   neighbor1A= SETfirstt_(facet1->neighbors, facetT);
   neighbor1B= SETsecondt_(facet1->neighbors, facetT);
   neighbor2A= SETfirstt_(facet2->neighbors, facetT);
   neighbor2B= SETsecondt_(facet2->neighbors, facetT);
   if (vertex1A == vertex2A) {
     vertexA= vertex1B;
     vertexB= vertex2B;
     neighborA= neighbor2A;
     neighborB= neighbor1A;
   }else if (vertex1A == vertex2B) {
     vertexA= vertex1B;
     vertexB= vertex2A;
     neighborA= neighbor2B;
     neighborB= neighbor1A;
   }else if (vertex1B == vertex2A) {
     vertexA= vertex1A;
     vertexB= vertex2B;
     neighborA= neighbor2A;
     neighborB= neighbor1B;
   }else { /* 1B == 2B */
     vertexA= vertex1A;
     vertexB= vertex2A;
     neighborA= neighbor2B;
     neighborB= neighbor1B;
   }
   /* vertexB always from facet2, neighborB always from facet1 */
   if (vertexA->id > vertexB->id) {
     SETfirst_(facet2->vertices)= vertexA;
     SETsecond_(facet2->vertices)= vertexB;
     if (vertexB == vertex2A)
       facet2->toporient= !facet2->toporient;
     SETfirst_(facet2->neighbors)= neighborA;
     SETsecond_(facet2->neighbors)= neighborB;
   }else {
     SETfirst_(facet2->vertices)= vertexB;
     SETsecond_(facet2->vertices)= vertexA;
     if (vertexB == vertex2B)
       facet2->toporient= !facet2->toporient;
     SETfirst_(facet2->neighbors)= neighborB;
     SETsecond_(facet2->neighbors)= neighborA;
   }
   qh_makeridges(neighborB);
   qh_setreplace(neighborB->neighbors, facet1, facet2);
   trace4((qh ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
        vertexA->id, neighborB->id, facet1->id, facet2->id));
 } /* mergefacet2d */
 
 
 /*---------------------------------
 
   qh_mergeneighbors( facet1, facet2 )
     merges the neighbors of facet1 into facet2
 
   see:
     qh_mergecycle_neighbors()
 
   design:
     for each neighbor of facet1
       if neighbor is also a neighbor of facet2
         if neighbor is simpilicial
           make ridges for later deletion as a degenerate facet
         update its neighbor set
       else
         move the neighbor relation to facet2
     remove the neighbor relation for facet1 and facet2
 */
 void qh_mergeneighbors(facetT *facet1, facetT *facet2) {
   facetT *neighbor, **neighborp;
 
   trace4((qh ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
           facet1->id, facet2->id));
   qh visit_id++;
   FOREACHneighbor_(facet2) {
     neighbor->visitid= qh visit_id;
   }
   FOREACHneighbor_(facet1) {
     if (neighbor->visitid == qh visit_id) {
       if (neighbor->simplicial)    /* is degen, needs ridges */
         qh_makeridges(neighbor);
       if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
         qh_setdel(neighbor->neighbors, facet1);
       else {
         qh_setdel(neighbor->neighbors, facet2);
         qh_setreplace(neighbor->neighbors, facet1, facet2);
       }
     }else if (neighbor != facet2) {
       qh_setappend(&(facet2->neighbors), neighbor);
       qh_setreplace(neighbor->neighbors, facet1, facet2);
     }
   }
   qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
   qh_setdel(facet2->neighbors, facet1);
 } /* mergeneighbors */
 
 
 /*---------------------------------
 
   qh_mergeridges( facet1, facet2 )
     merges the ridge set of facet1 into facet2
 
   returns:
     may delete all ridges for a vertex
     sets vertex->delridge on deleted ridges
 
   see:
     qh_mergecycle_ridges()
 
   design:
     delete ridges between facet1 and facet2
       mark (delridge) vertices on these ridges for later testing
     for each remaining ridge
       rename facet1 to facet2
 */
 void qh_mergeridges(facetT *facet1, facetT *facet2) {
   ridgeT *ridge, **ridgep;
   vertexT *vertex, **vertexp;
 
   trace4((qh ferr, 4038, "qh_mergeridges: merge ridges of f%d and f%d\n",
           facet1->id, facet2->id));
   FOREACHridge_(facet2->ridges) {
     if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
       FOREACHvertex_(ridge->vertices)
         vertex->delridge= True;
       qh_delridge(ridge);  /* expensive in high-d, could rebuild */
       ridgep--; /*repeat*/
     }
   }
   FOREACHridge_(facet1->ridges) {
     if (ridge->top == facet1)
       ridge->top= facet2;
     else
       ridge->bottom= facet2;
     qh_setappend(&(facet2->ridges), ridge);
   }
 } /* mergeridges */
 
 
 /*---------------------------------
 
   qh_mergesimplex( facet1, facet2, mergeapex )
     merge simplicial facet1 into facet2
     mergeapex==qh_MERGEapex if merging samecycle into horizon facet
       vertex id is latest (most recently created)
     facet1 may be contained in facet2
     ridges exist for both facets
 
   returns:
     facet2 with updated vertices, ridges, neighbors
     updated neighbors for facet1's vertices
     facet1 not deleted
     sets vertex->delridge on deleted ridges
 
   notes:
     special case code since this is the most common merge
     called from qh_mergefacet()
 
   design:
     if qh_MERGEapex
       add vertices of facet2 to qh.new_vertexlist if necessary
       add apex to facet2
     else
       for each ridge between facet1 and facet2
         set vertex->delridge
       determine the apex for facet1 (i.e., vertex to be merged)
       unless apex already in facet2
         insert apex into vertices for facet2
       add vertices of facet2 to qh.new_vertexlist if necessary
       add apex to qh.new_vertexlist if necessary
       for each vertex of facet1
         if apex
           rename facet1 to facet2 in its vertex neighbors
         else
           delete facet1 from vertex neighors
           if only in facet2
             add vertex to qh.del_vertices for later deletion
       for each ridge of facet1
         delete ridges between facet1 and facet2
         append other ridges to facet2 after renaming facet to facet2
 */
 void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex) {
   vertexT *vertex, **vertexp, *apex;
   ridgeT *ridge, **ridgep;
   boolT issubset= False;
   int vertex_i= -1, vertex_n;
   facetT *neighbor, **neighborp, *otherfacet;
 
   if (mergeapex) {
     if (!facet2->newfacet)
       qh_newvertices(facet2->vertices);  /* apex is new */
     apex= SETfirstt_(facet1->vertices, vertexT);
     if (SETfirstt_(facet2->vertices, vertexT) != apex)
       qh_setaddnth(&facet2->vertices, 0, apex);  /* apex has last id */
     else
       issubset= True;
   }else {
     zinc_(Zmergesimplex);
     FOREACHvertex_(facet1->vertices)
       vertex->seen= False;
     FOREACHridge_(facet1->ridges) {
       if (otherfacet_(ridge, facet1) == facet2) {
         FOREACHvertex_(ridge->vertices) {
           vertex->seen= True;
           vertex->delridge= True;
         }
         break;
       }
     }
     FOREACHvertex_(facet1->vertices) {
       if (!vertex->seen)
         break;  /* must occur */
     }
     apex= vertex;
     trace4((qh ferr, 4039, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
           apex->id, facet1->id, facet2->id));
     FOREACHvertex_i_(facet2->vertices) {
       if (vertex->id < apex->id) {
         break;
       }else if (vertex->id == apex->id) {
         issubset= True;
         break;
       }
     }
     if (!issubset)
       qh_setaddnth(&facet2->vertices, vertex_i, apex);
     if (!facet2->newfacet)
       qh_newvertices(facet2->vertices);
     else if (!apex->newlist) {
       qh_removevertex(apex);
       qh_appendvertex(apex);
     }
   }
   trace4((qh ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",
           facet1->id));
   FOREACHvertex_(facet1->vertices) {
     if (vertex == apex && !issubset)
       qh_setreplace(vertex->neighbors, facet1, facet2);
     else {
       qh_setdel(vertex->neighbors, facet1);
       if (!SETsecond_(vertex->neighbors))
         qh_mergevertex_del(vertex, facet1, facet2);
     }
   }
   trace4((qh ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
           facet1->id, facet2->id));
   qh visit_id++;
   FOREACHneighbor_(facet2)
     neighbor->visitid= qh visit_id;
   FOREACHridge_(facet1->ridges) {
     otherfacet= otherfacet_(ridge, facet1);
     if (otherfacet == facet2) {
       qh_setdel(facet2->ridges, ridge);
       qh_setfree(&(ridge->vertices));
       qh_memfree(ridge, (int)sizeof(ridgeT));
       qh_setdel(facet2->neighbors, facet1);
     }else {
       qh_setappend(&facet2->ridges, ridge);
       if (otherfacet->visitid != qh visit_id) {
         qh_setappend(&facet2->neighbors, otherfacet);
         qh_setreplace(otherfacet->neighbors, facet1, facet2);
         otherfacet->visitid= qh visit_id;
       }else {
         if (otherfacet->simplicial)    /* is degen, needs ridges */
           qh_makeridges(otherfacet);
         if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)
           qh_setdel(otherfacet->neighbors, facet1);
         else {   /*keep newfacet->neighbors->horizon*/
           qh_setdel(otherfacet->neighbors, facet2);
           qh_setreplace(otherfacet->neighbors, facet1, facet2);
         }
       }
       if (ridge->top == facet1) /* wait until after qh_makeridges */
         ridge->top= facet2;
       else
         ridge->bottom= facet2;
     }
   }
   SETfirst_(facet1->ridges)= NULL; /* it will be deleted */
   trace3((qh ferr, 3006, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",
           facet1->id, getid_(apex), facet2->id));
 } /* mergesimplex */
 
 /*---------------------------------
 
   qh_mergevertex_del( vertex, facet1, facet2 )
     delete a vertex because of merging facet1 into facet2
 
   returns:
     deletes vertex from facet2
     adds vertex to qh.del_vertices for later deletion
 */
 void qh_mergevertex_del(vertexT *vertex, facetT *facet1, facetT *facet2) {
 
   zinc_(Zmergevertex);
   trace2((qh ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
           vertex->id, facet1->id, facet2->id));
   qh_setdelsorted(facet2->vertices, vertex);
   vertex->deleted= True;
   qh_setappend(&qh del_vertices, vertex);
 } /* mergevertex_del */
 
 /*---------------------------------
 
   qh_mergevertex_neighbors( facet1, facet2 )
     merge the vertex neighbors of facet1 to facet2
 
   returns:
     if vertex is current qh.vertex_visit
       deletes facet1 from vertex->neighbors
     else
       renames facet1 to facet2 in vertex->neighbors
     deletes vertices if only one neighbor
 
   notes:
     assumes vertex neighbor sets are good
 */
 void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) {
   vertexT *vertex, **vertexp;
 
   trace4((qh ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
           facet1->id, facet2->id));
   if (qh tracevertex) {
     qh_fprintf(qh ferr, 8081, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",
              facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0].p);
     qh_errprint("TRACE", NULL, NULL, NULL, qh tracevertex);
   }
   FOREACHvertex_(facet1->vertices) {
     if (vertex->visitid != qh vertex_visit)
       qh_setreplace(vertex->neighbors, facet1, facet2);
     else {
       qh_setdel(vertex->neighbors, facet1);
       if (!SETsecond_(vertex->neighbors))
         qh_mergevertex_del(vertex, facet1, facet2);
     }
   }
   if (qh tracevertex)
     qh_errprint("TRACE", NULL, NULL, NULL, qh tracevertex);
 } /* mergevertex_neighbors */
 
 
 /*---------------------------------
 
   qh_mergevertices( vertices1, vertices2 )
     merges the vertex set of facet1 into facet2
 
   returns:
     replaces vertices2 with merged set
     preserves vertex_visit for qh_mergevertex_neighbors
     updates qh.newvertex_list
 
   design:
     create a merged set of both vertices (in inverse id order)
 */
 void qh_mergevertices(setT *vertices1, setT **vertices2) {
   int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1;
   setT *mergedvertices;
   vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
 
   mergedvertices= qh_settemp(newsize);
   FOREACHvertex_(vertices1) {
     if (!*vertex2 || vertex->id > (*vertex2)->id)
       qh_setappend(&mergedvertices, vertex);
     else {
       while (*vertex2 && (*vertex2)->id > vertex->id)
         qh_setappend(&mergedvertices, *vertex2++);
       if (!*vertex2 || (*vertex2)->id < vertex->id)
         qh_setappend(&mergedvertices, vertex);
       else
         qh_setappend(&mergedvertices, *vertex2++);
     }
   }
   while (*vertex2)
     qh_setappend(&mergedvertices, *vertex2++);
   if (newsize < qh_setsize(mergedvertices)) {
     qh_fprintf(qh ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   qh_setfree(vertices2);
   *vertices2= mergedvertices;
   qh_settemppop();
 } /* mergevertices */
 
 
 /*---------------------------------
 
   qh_neighbor_intersections( vertex )
     return intersection of all vertices in vertex->neighbors except for vertex
 
   returns:
     returns temporary set of vertices
     does not include vertex
     NULL if a neighbor is simplicial
     NULL if empty set
 
   notes:
     used for renaming vertices
 
   design:
     initialize the intersection set with vertices of the first two neighbors
     delete vertex from the intersection
     for each remaining neighbor
       intersect its vertex set with the intersection set
       return NULL if empty
     return the intersection set
 */
 setT *qh_neighbor_intersections(vertexT *vertex) {
   facetT *neighbor, **neighborp, *neighborA, *neighborB;
   setT *intersect;
   int neighbor_i, neighbor_n;
 
   FOREACHneighbor_(vertex) {
     if (neighbor->simplicial)
       return NULL;
   }
   neighborA= SETfirstt_(vertex->neighbors, facetT);
   neighborB= SETsecondt_(vertex->neighbors, facetT);
   zinc_(Zintersectnum);
   if (!neighborA)
     return NULL;
   if (!neighborB)
     intersect= qh_setcopy(neighborA->vertices, 0);
   else
     intersect= qh_vertexintersect_new(neighborA->vertices, neighborB->vertices);
   qh_settemppush(intersect);
   qh_setdelsorted(intersect, vertex);
   FOREACHneighbor_i_(vertex) {
     if (neighbor_i >= 2) {
       zinc_(Zintersectnum);
       qh_vertexintersect(&intersect, neighbor->vertices);
       if (!SETfirst_(intersect)) {
         zinc_(Zintersectfail);
         qh_settempfree(&intersect);
         return NULL;
       }
     }
   }
   trace3((qh ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
           qh_setsize(intersect), vertex->id));
   return intersect;
 } /* neighbor_intersections */
 
 /*---------------------------------
 
   qh_newvertices( vertices )
     add vertices to end of qh.vertex_list (marks as new vertices)
 
   returns:
     vertices on qh.newvertex_list
     vertex->newlist set
 */
 void qh_newvertices(setT *vertices) {
   vertexT *vertex, **vertexp;
 
   FOREACHvertex_(vertices) {
     if (!vertex->newlist) {
       qh_removevertex(vertex);
       qh_appendvertex(vertex);
     }
   }
 } /* newvertices */
 
 /*---------------------------------
 
   qh_reducevertices()
     reduce extra vertices, shared vertices, and redundant vertices
     facet->newmerge is set if merged since last call
     if !qh.MERGEvertices, only removes extra vertices
 
   returns:
     True if also merged degen_redundant facets
     vertices are renamed if possible
     clears facet->newmerge and vertex->delridge
 
   notes:
     ignored if 2-d
 
   design:
     merge any degenerate or redundant facets
     for each newly merged facet
       remove extra vertices
     if qh.MERGEvertices
       for each newly merged facet
         for each vertex
           if vertex was on a deleted ridge
             rename vertex if it is shared
       remove delridge flag from new vertices
 */
 boolT qh_reducevertices(void) {
   int numshare=0, numrename= 0;
   boolT degenredun= False;
   facetT *newfacet;
   vertexT *vertex, **vertexp;
 
   if (qh hull_dim == 2)
     return False;
   if (qh_merge_degenredundant())
     degenredun= True;
  LABELrestart:
   FORALLnew_facets {
     if (newfacet->newmerge) {
       if (!qh MERGEvertices)
         newfacet->newmerge= False;
       qh_remove_extravertices(newfacet);
     }
   }
   if (!qh MERGEvertices)
     return False;
   FORALLnew_facets {
     if (newfacet->newmerge) {
       newfacet->newmerge= False;
       FOREACHvertex_(newfacet->vertices) {
         if (vertex->delridge) {
           if (qh_rename_sharedvertex(vertex, newfacet)) {
             numshare++;
             vertexp--; /* repeat since deleted vertex */
           }
         }
       }
     }
   }
   FORALLvertex_(qh newvertex_list) {
     if (vertex->delridge && !vertex->deleted) {
       vertex->delridge= False;
       if (qh hull_dim >= 4 && qh_redundant_vertex(vertex)) {
         numrename++;
         if (qh_merge_degenredundant()) {
           degenredun= True;
           goto LABELrestart;
         }
       }
     }
   }
   trace1((qh ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
           numshare, numrename, degenredun));
   return degenredun;
 } /* reducevertices */
 
 /*---------------------------------
 
   qh_redundant_vertex( vertex )
     detect and rename a redundant vertex
     vertices have full vertex->neighbors
 
   returns:
     returns true if find a redundant vertex
       deletes vertex(vertex->deleted)
 
   notes:
     only needed if vertex->delridge and hull_dim >= 4
     may add degenerate facets to qh.facet_mergeset
     doesn't change vertex->neighbors or create redundant facets
 
   design:
     intersect vertices of all facet neighbors of vertex
     determine ridges for these vertices
     if find a new vertex for vertex amoung these ridges and vertices
       rename vertex to the new vertex
 */
 vertexT *qh_redundant_vertex(vertexT *vertex) {
   vertexT *newvertex= NULL;
   setT *vertices, *ridges;
 
   trace3((qh ferr, 3008, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));
   if ((vertices= qh_neighbor_intersections(vertex))) {
     ridges= qh_vertexridges(vertex);
     if ((newvertex= qh_find_newvertex(vertex, vertices, ridges)))
       qh_renamevertex(vertex, newvertex, ridges, NULL, NULL);
     qh_settempfree(&ridges);
     qh_settempfree(&vertices);
   }
   return newvertex;
 } /* redundant_vertex */
 
 /*---------------------------------
 
   qh_remove_extravertices( facet )
     remove extra vertices from non-simplicial facets
 
   returns:
     returns True if it finds them
 
   design:
     for each vertex in facet
       if vertex not in a ridge (i.e., no longer used)
         delete vertex from facet
         delete facet from vertice's neighbors
         unless vertex in another facet
           add vertex to qh.del_vertices for later deletion
 */
 boolT qh_remove_extravertices(facetT *facet) {
   ridgeT *ridge, **ridgep;
   vertexT *vertex, **vertexp;
   boolT foundrem= False;
 
   trace4((qh ferr, 4043, "qh_remove_extravertices: test f%d for extra vertices\n",
           facet->id));
   FOREACHvertex_(facet->vertices)
     vertex->seen= False;
   FOREACHridge_(facet->ridges) {
     FOREACHvertex_(ridge->vertices)
       vertex->seen= True;
   }
   FOREACHvertex_(facet->vertices) {
     if (!vertex->seen) {
       foundrem= True;
       zinc_(Zremvertex);
       qh_setdelsorted(facet->vertices, vertex);
       qh_setdel(vertex->neighbors, facet);
       if (!qh_setsize(vertex->neighbors)) {
         vertex->deleted= True;
         qh_setappend(&qh del_vertices, vertex);
         zinc_(Zremvertexdel);
         trace2((qh ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
       }else
         trace3((qh ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
       vertexp--; /*repeat*/
     }
   }
   return foundrem;
 } /* remove_extravertices */
 
 /*---------------------------------
 
   qh_rename_sharedvertex( vertex, facet )
     detect and rename if shared vertex in facet
     vertices have full ->neighbors
 
   returns:
     newvertex or NULL
     the vertex may still exist in other facets (i.e., a neighbor was pinched)
     does not change facet->neighbors
     updates vertex->neighbors
 
   notes:
     a shared vertex for a facet is only in ridges to one neighbor
     this may undo a pinched facet
 
     it does not catch pinches involving multiple facets.  These appear
       to be difficult to detect, since an exhaustive search is too expensive.
 
   design:
     if vertex only has two neighbors
       determine the ridges that contain the vertex
       determine the vertices shared by both neighbors
       if can find a new vertex in this set
         rename the vertex to the new vertex
 */
 vertexT *qh_rename_sharedvertex(vertexT *vertex, facetT *facet) {
   facetT *neighbor, **neighborp, *neighborA= NULL;
   setT *vertices, *ridges;
   vertexT *newvertex;
 
   if (qh_setsize(vertex->neighbors) == 2) {
     neighborA= SETfirstt_(vertex->neighbors, facetT);
     if (neighborA == facet)
       neighborA= SETsecondt_(vertex->neighbors, facetT);
   }else if (qh hull_dim == 3)
     return NULL;
   else {
     qh visit_id++;
     FOREACHneighbor_(facet)
       neighbor->visitid= qh visit_id;
     FOREACHneighbor_(vertex) {
       if (neighbor->visitid == qh visit_id) {
         if (neighborA)
           return NULL;
         neighborA= neighbor;
       }
     }
     if (!neighborA) {
       qh_fprintf(qh ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
         vertex->id, facet->id);
       qh_errprint("ERRONEOUS", facet, NULL, NULL, vertex);
       qh_errexit(qh_ERRqhull, NULL, NULL);
     }
   }
   /* the vertex is shared by facet and neighborA */
   ridges= qh_settemp(qh TEMPsize);
   neighborA->visitid= ++qh visit_id;
   qh_vertexridges_facet(vertex, facet, &ridges);
   trace2((qh ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",
     qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize(ridges), neighborA->id));
   zinc_(Zintersectnum);
   vertices= qh_vertexintersect_new(facet->vertices, neighborA->vertices);
   qh_setdel(vertices, vertex);
   qh_settemppush(vertices);
   if ((newvertex= qh_find_newvertex(vertex, vertices, ridges)))
     qh_renamevertex(vertex, newvertex, ridges, facet, neighborA);
   qh_settempfree(&vertices);
   qh_settempfree(&ridges);
   return newvertex;
 } /* rename_sharedvertex */
 
 /*---------------------------------
 
   qh_renameridgevertex( ridge, oldvertex, newvertex )
     renames oldvertex as newvertex in ridge
 
   returns:
 
   design:
     delete oldvertex from ridge
     if newvertex already in ridge
       copy ridge->noconvex to another ridge if possible
       delete the ridge
     else
       insert newvertex into the ridge
       adjust the ridge's orientation
 */
 void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
   int nth= 0, oldnth;
   facetT *temp;
   vertexT *vertex, **vertexp;
 
   oldnth= qh_setindex(ridge->vertices, oldvertex);
   qh_setdelnthsorted(ridge->vertices, oldnth);
   FOREACHvertex_(ridge->vertices) {
     if (vertex == newvertex) {
       zinc_(Zdelridge);
       if (ridge->nonconvex) /* only one ridge has nonconvex set */
         qh_copynonconvex(ridge);
       qh_delridge(ridge);
       trace2((qh ferr, 2038, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
         ridge->id, oldvertex->id, newvertex->id));
       return;
     }
     if (vertex->id < newvertex->id)
       break;
     nth++;
   }
   qh_setaddnth(&ridge->vertices, nth, newvertex);
   if (abs(oldnth - nth)%2) {
     trace3((qh ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
             ridge->id));
     temp= ridge->top;
     ridge->top= ridge->bottom;
     ridge->bottom= temp;
   }
 } /* renameridgevertex */
 
 
 /*---------------------------------
 
   qh_renamevertex( oldvertex, newvertex, ridges, oldfacet, neighborA )
     renames oldvertex as newvertex in ridges
     gives oldfacet/neighborA if oldvertex is shared between two facets
 
   returns:
     oldvertex may still exist afterwards
 
 
   notes:
     can not change neighbors of newvertex (since it's a subset)
 
   design:
     for each ridge in ridges
       rename oldvertex to newvertex and delete degenerate ridges
     if oldfacet not defined
       for each neighbor of oldvertex
         delete oldvertex from neighbor's vertices
         remove extra vertices from neighbor
       add oldvertex to qh.del_vertices
     else if oldvertex only between oldfacet and neighborA
       delete oldvertex from oldfacet and neighborA
       add oldvertex to qh.del_vertices
     else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
       delete oldvertex from oldfacet
       delete oldfacet from oldvertice's neighbors
       remove extra vertices (e.g., oldvertex) from neighborA
 */
 void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   boolT istrace= False;
 
   if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id ||
         newvertex->id == qh tracevertex_id)
     istrace= True;
   FOREACHridge_(ridges)
     qh_renameridgevertex(ridge, oldvertex, newvertex);
   if (!oldfacet) {
     zinc_(Zrenameall);
     if (istrace)
       qh_fprintf(qh ferr, 8082, "qh_renamevertex: renamed v%d to v%d in several facets\n",
                oldvertex->id, newvertex->id);
     FOREACHneighbor_(oldvertex) {
       qh_maydropneighbor(neighbor);
       qh_setdelsorted(neighbor->vertices, oldvertex);
       if (qh_remove_extravertices(neighbor))
         neighborp--; /* neighbor may be deleted */
     }
     if (!oldvertex->deleted) {
       oldvertex->deleted= True;
       qh_setappend(&qh del_vertices, oldvertex);
     }
   }else if (qh_setsize(oldvertex->neighbors) == 2) {
     zinc_(Zrenameshare);
     if (istrace)
       qh_fprintf(qh ferr, 8083, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n",
                oldvertex->id, newvertex->id, oldfacet->id);
     FOREACHneighbor_(oldvertex)
       qh_setdelsorted(neighbor->vertices, oldvertex);
     oldvertex->deleted= True;
     qh_setappend(&qh del_vertices, oldvertex);
   }else {
     zinc_(Zrenamepinch);
     if (istrace || qh IStracing)
       qh_fprintf(qh ferr, 8084, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n",
                oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
     qh_setdelsorted(oldfacet->vertices, oldvertex);
     qh_setdel(oldvertex->neighbors, oldfacet);
     qh_remove_extravertices(neighborA);
   }
 } /* renamevertex */
 
 
 /*---------------------------------
 
   qh_test_appendmerge( facet, neighbor )
     tests facet/neighbor for convexity
     appends to mergeset if non-convex
     if pre-merging,
       nop if qh.SKIPconvex, or qh.MERGEexact and coplanar
 
   returns:
     true if appends facet/neighbor to mergeset
     sets facet->center as needed
     does not change facet->seen
 
   design:
     if qh.cos_max is defined
       if the angle between facet normals is too shallow
         append an angle-coplanar merge to qh.mergeset
         return True
     make facet's centrum if needed
     if facet's centrum is above the neighbor
       set isconcave
     else
       if facet's centrum is not below the neighbor
         set iscoplanar
       make neighbor's centrum if needed
       if neighbor's centrum is above the facet
         set isconcave
       else if neighbor's centrum is not below the facet
         set iscoplanar
    if isconcave or iscoplanar
      get angle if needed
      append concave or coplanar merge to qh.mergeset
 */
 boolT qh_test_appendmerge(facetT *facet, facetT *neighbor) {
   realT dist, dist2= -REALmax, angle= -REALmax;
   boolT isconcave= False, iscoplanar= False, okangle= False;
 
   if (qh SKIPconvex && !qh POSTmerging)
     return False;
   if ((!qh MERGEexact || qh POSTmerging) && qh cos_max < REALmax/2) {
     angle= qh_getangle(facet->normal, neighbor->normal);
     zinc_(Zangletests);
     if (angle > qh cos_max) {
       zinc_(Zcoplanarangle);
       qh_appendmergeset(facet, neighbor, MRGanglecoplanar, &angle);
       trace2((qh ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
          angle, facet->id, neighbor->id));
       return True;
     }else
       okangle= True;
   }
   if (!facet->center)
     facet->center= qh_getcentrum(facet);
   zzinc_(Zcentrumtests);
   qh_distplane(facet->center, neighbor, &dist);
   if (dist > qh centrum_radius)
     isconcave= True;
   else {
     if (dist > -qh centrum_radius)
       iscoplanar= True;
     if (!neighbor->center)
       neighbor->center= qh_getcentrum(neighbor);
     zzinc_(Zcentrumtests);
     qh_distplane(neighbor->center, facet, &dist2);
     if (dist2 > qh centrum_radius)
       isconcave= True;
     else if (!iscoplanar && dist2 > -qh centrum_radius)
       iscoplanar= True;
   }
   if (!isconcave && (!iscoplanar || (qh MERGEexact && !qh POSTmerging)))
     return False;
   if (!okangle && qh ANGLEmerge) {
     angle= qh_getangle(facet->normal, neighbor->normal);
     zinc_(Zangletests);
   }
   if (isconcave) {
     zinc_(Zconcaveridge);
     if (qh ANGLEmerge)
       angle += qh_ANGLEconcave + 0.5;
     qh_appendmergeset(facet, neighbor, MRGconcave, &angle);
     trace0((qh ferr, 18, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",
            facet->id, neighbor->id, dist, dist2, angle, qh furthest_id));
   }else /* iscoplanar */ {
     zinc_(Zcoplanarcentrum);
     qh_appendmergeset(facet, neighbor, MRGcoplanar, &angle);
     trace2((qh ferr, 2040, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
               facet->id, neighbor->id, dist, dist2, angle));
   }
   return True;
 } /* test_appendmerge */
 
 /*---------------------------------
 
   qh_test_vneighbors()
     test vertex neighbors for convexity
     tests all facets on qh.newfacet_list
 
   returns:
     true if non-convex vneighbors appended to qh.facet_mergeset
     initializes vertex neighbors if needed
 
   notes:
     assumes all facet neighbors have been tested
     this can be expensive
     this does not guarantee that a centrum is below all facets
       but it is unlikely
     uses qh.visit_id
 
   design:
     build vertex neighbors if necessary
     for all new facets
       for all vertices
         for each unvisited facet neighbor of the vertex
           test new facet and neighbor for convexity
 */
 boolT qh_test_vneighbors(void /* qh.newfacet_list */) {
   facetT *newfacet, *neighbor, **neighborp;
   vertexT *vertex, **vertexp;
   int nummerges= 0;
 
   trace1((qh ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
   if (!qh VERTEXneighbors)
     qh_vertexneighbors();
   FORALLnew_facets
     newfacet->seen= False;
   FORALLnew_facets {
     newfacet->seen= True;
     newfacet->visitid= qh visit_id++;
     FOREACHneighbor_(newfacet)
       newfacet->visitid= qh visit_id;
     FOREACHvertex_(newfacet->vertices) {
       FOREACHneighbor_(vertex) {
         if (neighbor->seen || neighbor->visitid == qh visit_id)
           continue;
         if (qh_test_appendmerge(newfacet, neighbor))
           nummerges++;
       }
     }
   }
   zadd_(Ztestvneighbor, nummerges);
   trace1((qh ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
            nummerges));
   return (nummerges > 0);
 } /* test_vneighbors */
 
 /*---------------------------------
 
   qh_tracemerge( facet1, facet2 )
     print trace message after merge
 */
 void qh_tracemerge(facetT *facet1, facetT *facet2) {
   boolT waserror= False;
 
 #ifndef qh_NOtrace
   if (qh IStracing >= 4)
     qh_errprint("MERGED", facet2, NULL, NULL, NULL);
   if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newlist)) {
     qh_fprintf(qh ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh furthest_id);
     if (facet2 != qh tracefacet)
       qh_errprint("TRACE", qh tracefacet,
         (qh tracevertex && qh tracevertex->neighbors) ?
            SETfirstt_(qh tracevertex->neighbors, facetT) : NULL,
         NULL, qh tracevertex);
   }
   if (qh tracevertex) {
     if (qh tracevertex->deleted)
       qh_fprintf(qh ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
             qh furthest_id);
     else
       qh_checkvertex(qh tracevertex);
   }
   if (qh tracefacet) {
     qh_checkfacet(qh tracefacet, True, &waserror);
     if (waserror)
       qh_errexit(qh_ERRqhull, qh tracefacet, NULL);
   }
 #endif /* !qh_NOtrace */
   if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */
     qh_checkfacet(facet2, True, &waserror);
     if (waserror)
       qh_errexit(qh_ERRqhull, NULL, NULL);
   }
 } /* tracemerge */
 
 /*---------------------------------
 
   qh_tracemerging()
     print trace message during POSTmerging
 
   returns:
     updates qh.mergereport
 
   notes:
     called from qh_mergecycle() and qh_mergefacet()
 
   see:
     qh_buildtracing()
 */
 void qh_tracemerging(void) {
   realT cpu;
   int total;
   time_t timedata;
   struct tm *tp;
 
   qh mergereport= zzval_(Ztotmerge);
   time(&timedata);
   tp= localtime(&timedata);
   cpu= qh_CPUclock;
   cpu /= qh_SECticks;
   total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
   qh_fprintf(qh ferr, 8087, "\n\
 At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets.  The hull\n\
   contains %d facets and %d vertices.\n",
       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,
       total, qh num_facets - qh num_visible,
       qh num_vertices-qh_setsize(qh del_vertices));
 } /* tracemerging */
 
 /*---------------------------------
 
   qh_updatetested( facet1, facet2 )
     clear facet2->tested and facet1->ridge->tested for merge
 
   returns:
     deletes facet2->center unless it's already large
       if so, clears facet2->ridge->tested
 
   design:
     clear facet2->tested
     clear ridge->tested for facet1's ridges
     if facet2 has a centrum
       if facet2 is large
         set facet2->keepcentrum
       else if facet2 has 3 vertices due to many merges, or not large and post merging
         clear facet2->keepcentrum
       unless facet2->keepcentrum
         clear facet2->center to recompute centrum later
         clear ridge->tested for facet2's ridges
 */
 void qh_updatetested(facetT *facet1, facetT *facet2) {
   ridgeT *ridge, **ridgep;
   int size;
 
   facet2->tested= False;
   FOREACHridge_(facet1->ridges)
     ridge->tested= False;
   if (!facet2->center)
     return;
   size= qh_setsize(facet2->vertices);
   if (!facet2->keepcentrum) {
     if (size > qh hull_dim + qh_MAXnewcentrum) {
       facet2->keepcentrum= True;
       zinc_(Zwidevertices);
     }
   }else if (size <= qh hull_dim + qh_MAXnewcentrum) {
     /* center and keepcentrum was set */
     if (size == qh hull_dim || qh POSTmerging)
       facet2->keepcentrum= False; /* if many merges need to recompute centrum */
   }
   if (!facet2->keepcentrum) {
     qh_memfree(facet2->center, qh normal_size);
     facet2->center= NULL;
     FOREACHridge_(facet2->ridges)
       ridge->tested= False;
   }
 } /* updatetested */
 
 /*---------------------------------
 
   qh_vertexridges( vertex )
     return temporary set of ridges adjacent to a vertex
     vertex->neighbors defined
 
   ntoes:
     uses qh.visit_id
     does not include implicit ridges for simplicial facets
 
   design:
     for each neighbor of vertex
       add ridges that include the vertex to ridges
 */
 setT *qh_vertexridges(vertexT *vertex) {
   facetT *neighbor, **neighborp;
   setT *ridges= qh_settemp(qh TEMPsize);
   int size;
 
   qh visit_id++;
   FOREACHneighbor_(vertex)
     neighbor->visitid= qh visit_id;
   FOREACHneighbor_(vertex) {
     if (*neighborp)   /* no new ridges in last neighbor */
       qh_vertexridges_facet(vertex, neighbor, &ridges);
   }
   if (qh PRINTstatistics || qh IStracing) {
     size= qh_setsize(ridges);
     zinc_(Zvertexridge);
     zadd_(Zvertexridgetot, size);
     zmax_(Zvertexridgemax, size);
     trace3((qh ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",
              size, vertex->id));
   }
   return ridges;
 } /* vertexridges */
 
 /*---------------------------------
 
   qh_vertexridges_facet( vertex, facet, ridges )
     add adjacent ridges for vertex in facet
     neighbor->visitid==qh.visit_id if it hasn't been visited
 
   returns:
     ridges updated
     sets facet->visitid to qh.visit_id-1
 
   design:
     for each ridge of facet
       if ridge of visited neighbor (i.e., unprocessed)
         if vertex in ridge
           append ridge to vertex
     mark facet processed
 */
 void qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges) {
   ridgeT *ridge, **ridgep;
   facetT *neighbor;
 
   FOREACHridge_(facet->ridges) {
     neighbor= otherfacet_(ridge, facet);
     if (neighbor->visitid == qh visit_id
     && qh_setin(ridge->vertices, vertex))
       qh_setappend(ridges, ridge);
   }
   facet->visitid= qh visit_id-1;
 } /* vertexridges_facet */
 
 /*---------------------------------
 
   qh_willdelete( facet, replace )
     moves facet to visible list
     sets facet->f.replace to replace (may be NULL)
 
   returns:
     bumps qh.num_visible
 */
 void qh_willdelete(facetT *facet, facetT *replace) {
 
   qh_removefacet(facet);
   qh_prependfacet(facet, &qh visible_list);
   qh num_visible++;
   facet->visible= True;
   facet->f.replace= replace;
 } /* willdelete */
 
 #else /* qh_NOmerge */
 void qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle) {
 }
 void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
                       boolT vneighbors) {
 }
 boolT qh_checkzero(boolT testall) {
    }
 #endif /* qh_NOmerge */
 
diff --git a/src/libqhull/merge.h b/src/libqhull/merge.h
index 944982f..29a9a88 100644
--- a/src/libqhull/merge.h
+++ b/src/libqhull/merge.h
@@ -1,178 +1,178 @@
 /*
  ---------------------------------
 
    merge.h
    header file for merge.c
 
    see qh-merge.htm and merge.c
 
-   Copyright (c) 1993-2014 C.B. Barber.
-   $Id: //main/2011/qhull/src/libqhull/merge.h#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 C.B. Barber.
+   $Id: //main/2011/qhull/src/libqhull/merge.h#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFmerge
 #define qhDEFmerge 1
 
 #include "libqhull.h"
 
 
 /*============ -constants- ==============*/
 
 /*----------------------------------
 
   qh_ANGLEredundant
     indicates redundant merge in mergeT->angle
 */
 #define qh_ANGLEredundant 6.0
 
 /*----------------------------------
 
   qh_ANGLEdegen
     indicates degenerate facet in mergeT->angle
 */
 #define qh_ANGLEdegen     5.0
 
 /*----------------------------------
 
   qh_ANGLEconcave
     offset to indicate concave facets in mergeT->angle
 
   notes:
     concave facets are assigned the range of [2,4] in mergeT->angle
     roundoff error may make the angle less than 2
 */
 #define qh_ANGLEconcave  1.5
 
 /*----------------------------------
 
   MRG... (mergeType)
     indicates the type of a merge (mergeT->type)
 */
 typedef enum {  /* in sort order for facet_mergeset */
   MRGnone= 0,
   MRGcoplanar,          /* centrum coplanar */
   MRGanglecoplanar,     /* angle coplanar */
                         /* could detect half concave ridges */
   MRGconcave,           /* concave ridge */
   MRGflip,              /* flipped facet. facet1 == facet2 */
   MRGridge,             /* duplicate ridge (qh_MERGEridge) */
                         /* degen and redundant go onto degen_mergeset */
   MRGdegen,             /* degenerate facet (!enough neighbors) facet1 == facet2 */
   MRGredundant,         /* redundant facet (vertex subset) */
                         /* merge_degenredundant assumes degen < redundant */
   MRGmirror,            /* mirror facet from qh_triangulate */
   ENDmrg
 } mergeType;
 
 /*----------------------------------
 
   qh_MERGEapex
     flag for qh_mergefacet() to indicate an apex merge
 */
 #define qh_MERGEapex     True
 
 /*============ -structures- ====================*/
 
 /*----------------------------------
 
   mergeT
     structure used to merge facets
 */
 
 typedef struct mergeT mergeT;
 struct mergeT {         /* initialize in qh_appendmergeset */
   realT   angle;        /* angle between normals of facet1 and facet2 */
   facetT *facet1;       /* will merge facet1 into facet2 */
   facetT *facet2;
   mergeType type;
 };
 
 
 /*=========== -macros- =========================*/
 
 /*----------------------------------
 
   FOREACHmerge_( merges ) {...}
     assign 'merge' to each merge in merges
 
   notes:
     uses 'mergeT *merge, **mergep;'
     if qh_mergefacet(),
       restart since qh.facet_mergeset may change
     see FOREACHsetelement_
 */
 #define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
 
 /*============ prototypes in alphabetical order after pre/postmerge =======*/
 
 void    qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle);
 void    qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
              boolT vneighbors);
 void    qh_all_merges(boolT othermerge, boolT vneighbors);
 void    qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
 setT   *qh_basevertices( facetT *samecycle);
 void    qh_checkconnect(void /* qh.new_facets */);
 boolT   qh_checkzero(boolT testall);
 int     qh_compareangle(const void *p1, const void *p2);
 int     qh_comparemerge(const void *p1, const void *p2);
 int     qh_comparevisit(const void *p1, const void *p2);
 void    qh_copynonconvex(ridgeT *atridge);
 void    qh_degen_redundant_facet(facetT *facet);
 void    qh_degen_redundant_neighbors(facetT *facet, facetT *delfacet);
 vertexT *qh_find_newvertex(vertexT *oldvertex, setT *vertices, setT *ridges);
 void    qh_findbest_test(boolT testcentrum, facetT *facet, facetT *neighbor,
            facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
 facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
 void    qh_flippedmerges(facetT *facetlist, boolT *wasmerge);
 void    qh_forcedmerges( boolT *wasmerge);
 void    qh_getmergeset(facetT *facetlist);
 void    qh_getmergeset_initial(facetT *facetlist);
 void    qh_hashridge(setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
 ridgeT *qh_hashridge_find(setT *hashtable, int hashsize, ridgeT *ridge,
               vertexT *vertex, vertexT *oldvertex, int *hashslot);
 void    qh_makeridges(facetT *facet);
 void    qh_mark_dupridges(facetT *facetlist);
 void    qh_maydropneighbor(facetT *facet);
 int     qh_merge_degenredundant(void);
 void    qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype);
 void    qh_mergecycle(facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_all(facetT *facetlist, boolT *wasmerge);
 void    qh_mergecycle_facets( facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet);
 void    qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
 void    qh_mergefacet2d(facetT *facet1, facetT *facet2);
 void    qh_mergeneighbors(facetT *facet1, facetT *facet2);
 void    qh_mergeridges(facetT *facet1, facetT *facet2);
 void    qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex);
 void    qh_mergevertex_del(vertexT *vertex, facetT *facet1, facetT *facet2);
 void    qh_mergevertex_neighbors(facetT *facet1, facetT *facet2);
 void    qh_mergevertices(setT *vertices1, setT **vertices);
 setT   *qh_neighbor_intersections(vertexT *vertex);
 void    qh_newvertices(setT *vertices);
 boolT   qh_reducevertices(void);
 vertexT *qh_redundant_vertex(vertexT *vertex);
 boolT   qh_remove_extravertices(facetT *facet);
 vertexT *qh_rename_sharedvertex(vertexT *vertex, facetT *facet);
 void    qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
 void    qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges,
                         facetT *oldfacet, facetT *neighborA);
 boolT   qh_test_appendmerge(facetT *facet, facetT *neighbor);
 boolT   qh_test_vneighbors(void /* qh.newfacet_list */);
 void    qh_tracemerge(facetT *facet1, facetT *facet2);
 void    qh_tracemerging(void);
 void    qh_updatetested( facetT *facet1, facetT *facet2);
 setT   *qh_vertexridges(vertexT *vertex);
 void    qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges);
 void    qh_willdelete(facetT *facet, facetT *replace);
 
 #endif /* qhDEFmerge */
diff --git a/src/libqhull/poly.c b/src/libqhull/poly.c
index 7a8bd79..cfb0e7b 100644
--- a/src/libqhull/poly.c
+++ b/src/libqhull/poly.c
@@ -1,1199 +1,1199 @@
 /*
  ---------------------------------
 
    poly.c
    implements polygons and simplices
 
    see qh-poly.htm, poly.h and libqhull.h
 
    infrequent code is in poly2.c
    (all but top 50 and their callers 12/3/95)
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/poly.c#6 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/poly.c#8 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_a.h"
 
 /*======== functions in alphabetical order ==========*/
 
 /*---------------------------------
 
   qh_appendfacet( facet )
     appends facet to end of qh.facet_list,
 
   returns:
     updates qh.newfacet_list, facet_next, facet_list
     increments qh.numfacets
 
   notes:
     assumes qh.facet_list/facet_tail is defined (createsimplex)
 
   see:
     qh_removefacet()
 
 */
 void qh_appendfacet(facetT *facet) {
   facetT *tail= qh facet_tail;
 
   if (tail == qh newfacet_list)
     qh newfacet_list= facet;
   if (tail == qh facet_next)
     qh facet_next= facet;
   facet->previous= tail->previous;
   facet->next= tail;
   if (tail->previous)
     tail->previous->next= facet;
   else
     qh facet_list= facet;
   tail->previous= facet;
   qh num_facets++;
   trace4((qh ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));
 } /* appendfacet */
 
 
 /*---------------------------------
 
   qh_appendvertex( vertex )
     appends vertex to end of qh.vertex_list,
 
   returns:
     sets vertex->newlist
     updates qh.vertex_list, newvertex_list
     increments qh.num_vertices
 
   notes:
     assumes qh.vertex_list/vertex_tail is defined (createsimplex)
 
 */
 void qh_appendvertex(vertexT *vertex) {
   vertexT *tail= qh vertex_tail;
 
   if (tail == qh newvertex_list)
     qh newvertex_list= vertex;
   vertex->newlist= True;
   vertex->previous= tail->previous;
   vertex->next= tail;
   if (tail->previous)
     tail->previous->next= vertex;
   else
     qh vertex_list= vertex;
   tail->previous= vertex;
   qh num_vertices++;
   trace4((qh ferr, 4045, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));
 } /* appendvertex */
 
 
 /*---------------------------------
 
   qh_attachnewfacets( )
     attach horizon facets to new facets in qh.newfacet_list
     newfacets have neighbor and ridge links to horizon but not vice versa
     only needed for qh.ONLYgood
 
   returns:
     set qh.NEWfacets
     horizon facets linked to new facets
       ridges changed from visible facets to new facets
       simplicial ridges deleted
     qh.visible_list, no ridges valid
     facet->f.replace is a newfacet (if any)
 
   design:
     delete interior ridges and neighbor sets by
       for each visible, non-simplicial facet
         for each ridge
           if last visit or if neighbor is simplicial
             if horizon neighbor
               delete ridge for horizon's ridge set
             delete ridge
         erase neighbor set
     attach horizon facets and new facets by
       for all new facets
         if corresponding horizon facet is simplicial
           locate corresponding visible facet {may be more than one}
           link visible facet to new facet
           replace visible facet with new facet in horizon
         else it's non-simplicial
           for all visible neighbors of the horizon facet
             link visible neighbor to new facet
             delete visible neighbor from horizon facet
           append new facet to horizon's neighbors
           the first ridge of the new facet is the horizon ridge
           link the new facet into the horizon ridge
 */
 void qh_attachnewfacets(void /* qh.visible_list, newfacet_list */) {
   facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
   ridgeT *ridge, **ridgep;
 
   qh NEWfacets= True;
   trace3((qh ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));
   qh visit_id++;
   FORALLvisible_facets {
     visible->visitid= qh visit_id;
     if (visible->ridges) {
       FOREACHridge_(visible->ridges) {
         neighbor= otherfacet_(ridge, visible);
         if (neighbor->visitid == qh visit_id
             || (!neighbor->visible && neighbor->simplicial)) {
           if (!neighbor->visible)  /* delete ridge for simplicial horizon */
             qh_setdel(neighbor->ridges, ridge);
           qh_setfree(&(ridge->vertices)); /* delete on 2nd visit */
           qh_memfree(ridge, (int)sizeof(ridgeT));
         }
       }
       SETfirst_(visible->ridges)= NULL;
     }
     SETfirst_(visible->neighbors)= NULL;
   }
   trace1((qh ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));
   FORALLnew_facets {
     horizon= SETfirstt_(newfacet->neighbors, facetT);
     if (horizon->simplicial) {
       visible= NULL;
       FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
         if (neighbor->visible) {
           if (visible) {
             if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,
                                   SETindex_(horizon->neighbors, neighbor))) {
               visible= neighbor;
               break;
             }
           }else
             visible= neighbor;
         }
       }
       if (visible) {
         visible->f.replace= newfacet;
         qh_setreplace(horizon->neighbors, visible, newfacet);
       }else {
         qh_fprintf(qh ferr, 6102, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n",
                  horizon->id, newfacet->id);
         qh_errexit2(qh_ERRqhull, horizon, newfacet);
       }
     }else { /* non-simplicial, with a ridge for newfacet */
       FOREACHneighbor_(horizon) {    /* may hold for many new facets */
         if (neighbor->visible) {
           neighbor->f.replace= newfacet;
           qh_setdelnth(horizon->neighbors,
                         SETindex_(horizon->neighbors, neighbor));
           neighborp--; /* repeat */
         }
       }
       qh_setappend(&horizon->neighbors, newfacet);
       ridge= SETfirstt_(newfacet->ridges, ridgeT);
       if (ridge->top == horizon)
         ridge->bottom= newfacet;
       else
         ridge->top= newfacet;
       }
   } /* newfacets */
   if (qh PRINTstatistics) {
     FORALLvisible_facets {
       if (!visible->f.replace)
         zinc_(Zinsidevisible);
     }
   }
 } /* attachnewfacets */
 
 /*---------------------------------
 
   qh_checkflipped( facet, dist, allerror )
     checks facet orientation to interior point
 
     if allerror set,
       tests against qh.DISTround
     else
       tests against 0 since tested against DISTround before
 
   returns:
     False if it flipped orientation (sets facet->flipped)
     distance if non-NULL
 */
 boolT qh_checkflipped(facetT *facet, realT *distp, boolT allerror) {
   realT dist;
 
   if (facet->flipped && !distp)
     return False;
   zzinc_(Zdistcheck);
   qh_distplane(qh interior_point, facet, &dist);
   if (distp)
     *distp= dist;
   if ((allerror && dist > -qh DISTround)|| (!allerror && dist >= 0.0)) {
     facet->flipped= True;
     zzinc_(Zflippedfacets);
     trace0((qh ferr, 19, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n",
               facet->id, dist, qh furthest_id));
     qh_precision("flipped facet");
     return False;
   }
   return True;
 } /* checkflipped */
 
 /*---------------------------------
 
   qh_delfacet( facet )
     removes facet from facet_list and frees up its memory
 
   notes:
     assumes vertices and ridges already freed
 */
 void qh_delfacet(facetT *facet) {
   void **freelistp; /* used !qh_NOmem */
 
   trace4((qh ferr, 4046, "qh_delfacet: delete f%d\n", facet->id));
   if (facet == qh tracefacet)
     qh tracefacet= NULL;
   if (facet == qh GOODclosest)
     qh GOODclosest= NULL;
   qh_removefacet(facet);
   if (!facet->tricoplanar || facet->keepcentrum) {
     qh_memfree_(facet->normal, qh normal_size, freelistp);
     if (qh CENTERtype == qh_ASvoronoi) {   /* uses macro calls */
       qh_memfree_(facet->center, qh center_size, freelistp);
     }else /* AScentrum */ {
       qh_memfree_(facet->center, qh normal_size, freelistp);
     }
   }
   qh_setfree(&(facet->neighbors));
   if (facet->ridges)
     qh_setfree(&(facet->ridges));
   qh_setfree(&(facet->vertices));
   if (facet->outsideset)
     qh_setfree(&(facet->outsideset));
   if (facet->coplanarset)
     qh_setfree(&(facet->coplanarset));
   qh_memfree_(facet, (int)sizeof(facetT), freelistp);
 } /* delfacet */
 
 
 /*---------------------------------
 
   qh_deletevisible()
     delete visible facets and vertices
 
   returns:
     deletes each facet and removes from facetlist
     at exit, qh.visible_list empty (== qh.newfacet_list)
 
   notes:
     ridges already deleted
     horizon facets do not reference facets on qh.visible_list
     new facets in qh.newfacet_list
     uses   qh.visit_id;
 */
 void qh_deletevisible(void /*qh.visible_list*/) {
   facetT *visible, *nextfacet;
   vertexT *vertex, **vertexp;
   int numvisible= 0, numdel= qh_setsize(qh del_vertices);
 
   trace1((qh ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",
          qh num_visible, numdel));
   for (visible= qh visible_list; visible && visible->visible;
                 visible= nextfacet) { /* deleting current */
     nextfacet= visible->next;
     numvisible++;
     qh_delfacet(visible);
   }
   if (numvisible != qh num_visible) {
     qh_fprintf(qh ferr, 6103, "qhull internal error (qh_deletevisible): qh num_visible %d is not number of visible facets %d\n",
              qh num_visible, numvisible);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   qh num_visible= 0;
   zadd_(Zvisfacettot, numvisible);
   zmax_(Zvisfacetmax, numvisible);
   zzadd_(Zdelvertextot, numdel);
   zmax_(Zdelvertexmax, numdel);
   FOREACHvertex_(qh del_vertices)
     qh_delvertex(vertex);
   qh_settruncate(qh del_vertices, 0);
 } /* deletevisible */
 
 /*---------------------------------
 
   qh_facetintersect( facetA, facetB, skipa, skipB, prepend )
     return vertices for intersection of two simplicial facets
     may include 1 prepended entry (if more, need to settemppush)
 
   returns:
     returns set of qh.hull_dim-1 + prepend vertices
     returns skipped index for each test and checks for exactly one
 
   notes:
     does not need settemp since set in quick memory
 
   see also:
     qh_vertexintersect and qh_vertexintersect_new
     use qh_setnew_delnthsorted to get nth ridge (no skip information)
 
   design:
     locate skipped vertex by scanning facet A's neighbors
     locate skipped vertex by scanning facet B's neighbors
     intersect the vertex sets
 */
 setT *qh_facetintersect(facetT *facetA, facetT *facetB,
                          int *skipA,int *skipB, int prepend) {
   setT *intersect;
   int dim= qh hull_dim, i, j;
   facetT **neighborsA, **neighborsB;
 
   neighborsA= SETaddr_(facetA->neighbors, facetT);
   neighborsB= SETaddr_(facetB->neighbors, facetT);
   i= j= 0;
   if (facetB == *neighborsA++)
     *skipA= 0;
   else if (facetB == *neighborsA++)
     *skipA= 1;
   else if (facetB == *neighborsA++)
     *skipA= 2;
   else {
     for (i=3; i < dim; i++) {
       if (facetB == *neighborsA++) {
         *skipA= i;
         break;
       }
     }
   }
   if (facetA == *neighborsB++)
     *skipB= 0;
   else if (facetA == *neighborsB++)
     *skipB= 1;
   else if (facetA == *neighborsB++)
     *skipB= 2;
   else {
     for (j=3; j < dim; j++) {
       if (facetA == *neighborsB++) {
         *skipB= j;
         break;
       }
     }
   }
   if (i >= dim || j >= dim) {
     qh_fprintf(qh ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n",
             facetA->id, facetB->id);
     qh_errexit2(qh_ERRqhull, facetA, facetB);
   }
   intersect= qh_setnew_delnthsorted(facetA->vertices, qh hull_dim, *skipA, prepend);
   trace4((qh ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
           facetA->id, *skipA, facetB->id, *skipB));
   return(intersect);
 } /* facetintersect */
 
 /*---------------------------------
 
   qh_gethash( hashsize, set, size, firstindex, skipelem )
     return hashvalue for a set with firstindex and skipelem
 
   notes:
     returned hash is in [0,hashsize)
     assumes at least firstindex+1 elements
     assumes skipelem is NULL, in set, or part of hash
 
     hashes memory addresses which may change over different runs of the same data
     using sum for hash does badly in high d
 */
 int qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem) {
   void **elemp= SETelemaddr_(set, firstindex, void);
   ptr_intT hash = 0, elem;
   unsigned result;
   int i;
 #ifdef _MSC_VER                   /* Microsoft Visual C++ -- warn about 64-bit issues */
 #pragma warning( push)            /* WARN64 -- ptr_intT holds a 64-bit pointer */
 #pragma warning( disable : 4311)  /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */
 #endif
 
   switch (size-firstindex) {
   case 1:
     hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
     break;
   case 2:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
     break;
   case 3:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       - (ptr_intT) skipelem;
     break;
   case 4:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
     break;
   case 5:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
     break;
   case 6:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
       - (ptr_intT) skipelem;
     break;
   default:
     hash= 0;
     i= 3;
     do {     /* this is about 10% in 10-d */
       if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
         hash ^= (elem << i) + (elem >> (32-i));
         i += 3;
         if (i >= 32)
           i -= 32;
       }
     }while (*elemp);
     break;
   }
   if (hashsize<0) {
     qh_fprintf(qh ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly.c]\n", hashsize);
     qh_errexit2(qh_ERRqhull, NULL, NULL);
   }
   result= (unsigned)hash;
   result %= (unsigned)hashsize;
   /* result= 0; for debugging */
   return result;
 #ifdef _MSC_VER
 #pragma warning( pop)
 #endif
 } /* gethash */
 
 /*---------------------------------
 
   qh_makenewfacet( vertices, toporient, horizon )
     creates a toporient? facet from vertices
 
   returns:
     returns newfacet
       adds newfacet to qh.facet_list
       newfacet->vertices= vertices
       if horizon
         newfacet->neighbor= horizon, but not vice versa
     newvertex_list updated with vertices
 */
 facetT *qh_makenewfacet(setT *vertices, boolT toporient,facetT *horizon) {
   facetT *newfacet;
   vertexT *vertex, **vertexp;
 
   FOREACHvertex_(vertices) {
     if (!vertex->newlist) {
       qh_removevertex(vertex);
       qh_appendvertex(vertex);
     }
   }
   newfacet= qh_newfacet();
   newfacet->vertices= vertices;
   newfacet->toporient= (unsigned char)toporient;
   if (horizon)
     qh_setappend(&(newfacet->neighbors), horizon);
   qh_appendfacet(newfacet);
   return(newfacet);
 } /* makenewfacet */
 
 
 /*---------------------------------
 
   qh_makenewplanes()
     make new hyperplanes for facets on qh.newfacet_list
 
   returns:
     all facets have hyperplanes or are marked for   merging
     doesn't create hyperplane if horizon is coplanar (will merge)
     updates qh.min_vertex if qh.JOGGLEmax
 
   notes:
     facet->f.samecycle is defined for facet->mergehorizon facets
 */
 void qh_makenewplanes(void /* newfacet_list */) {
   facetT *newfacet;
 
   FORALLnew_facets {
     if (!newfacet->mergehorizon)
       qh_setfacetplane(newfacet);
   }
   if (qh JOGGLEmax < REALmax/2)
     minimize_(qh min_vertex, -wwval_(Wnewvertexmax));
 } /* makenewplanes */
 
 /*---------------------------------
 
   qh_makenew_nonsimplicial( visible, apex, numnew )
     make new facets for ridges of a visible facet
 
   returns:
     first newfacet, bumps numnew as needed
     attaches new facets if !qh.ONLYgood
     marks ridge neighbors for simplicial visible
     if (qh.ONLYgood)
       ridges on newfacet, horizon, and visible
     else
       ridge and neighbors between newfacet and   horizon
       visible facet's ridges are deleted
 
   notes:
     qh.visit_id if visible has already been processed
     sets neighbor->seen for building f.samecycle
       assumes all 'seen' flags initially false
 
   design:
     for each ridge of visible facet
       get neighbor of visible facet
       if neighbor was already processed
         delete the ridge (will delete all visible facets later)
       if neighbor is a horizon facet
         create a new facet
         if neighbor coplanar
           adds newfacet to f.samecycle for later merging
         else
           updates neighbor's neighbor set
           (checks for non-simplicial facet with multiple ridges to visible facet)
         updates neighbor's ridge set
         (checks for simplicial neighbor to non-simplicial visible facet)
         (deletes ridge if neighbor is simplicial)
 
 */
 #ifndef qh_NOmerge
 facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew) {
   void **freelistp; /* used !qh_NOmem */
   ridgeT *ridge, **ridgep;
   facetT *neighbor, *newfacet= NULL, *samecycle;
   setT *vertices;
   boolT toporient;
   int ridgeid;
 
   FOREACHridge_(visible->ridges) {
     ridgeid= ridge->id;
     neighbor= otherfacet_(ridge, visible);
     if (neighbor->visible) {
       if (!qh ONLYgood) {
         if (neighbor->visitid == qh visit_id) {
           qh_setfree(&(ridge->vertices));  /* delete on 2nd visit */
           qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
         }
       }
     }else {  /* neighbor is an horizon facet */
       toporient= (ridge->top == visible);
       vertices= qh_setnew(qh hull_dim); /* makes sure this is quick */
       qh_setappend(&vertices, apex);
       qh_setappend_set(&vertices, ridge->vertices);
       newfacet= qh_makenewfacet(vertices, toporient, neighbor);
       (*numnew)++;
       if (neighbor->coplanar) {
         newfacet->mergehorizon= True;
         if (!neighbor->seen) {
           newfacet->f.samecycle= newfacet;
           neighbor->f.newcycle= newfacet;
         }else {
           samecycle= neighbor->f.newcycle;
           newfacet->f.samecycle= samecycle->f.samecycle;
           samecycle->f.samecycle= newfacet;
         }
       }
       if (qh ONLYgood) {
         if (!neighbor->simplicial)
           qh_setappend(&(newfacet->ridges), ridge);
       }else {  /* qh_attachnewfacets */
         if (neighbor->seen) {
           if (neighbor->simplicial) {
             qh_fprintf(qh ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",
                    neighbor->id, visible->id);
             qh_errexit2(qh_ERRqhull, neighbor, visible);
           }
           qh_setappend(&(neighbor->neighbors), newfacet);
         }else
           qh_setreplace(neighbor->neighbors, visible, newfacet);
         if (neighbor->simplicial) {
           qh_setdel(neighbor->ridges, ridge);
           qh_setfree(&(ridge->vertices));
           qh_memfree(ridge, (int)sizeof(ridgeT));
         }else {
           qh_setappend(&(newfacet->ridges), ridge);
           if (toporient)
             ridge->top= newfacet;
           else
             ridge->bottom= newfacet;
         }
       trace4((qh ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
             newfacet->id, apex->id, ridgeid, neighbor->id));
       }
     }
     neighbor->seen= True;
   } /* for each ridge */
   if (!qh ONLYgood)
     SETfirst_(visible->ridges)= NULL;
   return newfacet;
 } /* makenew_nonsimplicial */
 #else /* qh_NOmerge */
 facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew) {
   return NULL;
 }
 #endif /* qh_NOmerge */
 
 /*---------------------------------
 
   qh_makenew_simplicial( visible, apex, numnew )
     make new facets for simplicial visible facet and apex
 
   returns:
     attaches new facets if (!qh.ONLYgood)
       neighbors between newfacet and horizon
 
   notes:
     nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial)
 
   design:
     locate neighboring horizon facet for visible facet
     determine vertices and orientation
     create new facet
     if coplanar,
       add new facet to f.samecycle
     update horizon facet's neighbor list
 */
 facetT *qh_makenew_simplicial(facetT *visible, vertexT *apex, int *numnew) {
   facetT *neighbor, **neighborp, *newfacet= NULL;
   setT *vertices;
   boolT flip, toporient;
   int horizonskip, visibleskip;
 
   FOREACHneighbor_(visible) {
     if (!neighbor->seen && !neighbor->visible) {
       vertices= qh_facetintersect(neighbor,visible, &horizonskip, &visibleskip, 1);
       SETfirst_(vertices)= apex;
       flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));
       if (neighbor->toporient)
         toporient= horizonskip & 0x1;
       else
         toporient= (horizonskip & 0x1) ^ 0x1;
       newfacet= qh_makenewfacet(vertices, toporient, neighbor);
       (*numnew)++;
       if (neighbor->coplanar && (qh PREmerge || qh MERGEexact)) {
 #ifndef qh_NOmerge
         newfacet->f.samecycle= newfacet;
         newfacet->mergehorizon= True;
 #endif
       }
       if (!qh ONLYgood)
         SETelem_(neighbor->neighbors, horizonskip)= newfacet;
       trace4((qh ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
             newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
               neighbor->toporient, visible->id, visibleskip, flip));
     }
   }
   return newfacet;
 } /* makenew_simplicial */
 
 /*---------------------------------
 
   qh_matchneighbor( newfacet, newskip, hashsize, hashcount )
     either match subridge of newfacet with neighbor or add to hash_table
 
   returns:
     duplicate ridges are unmatched and marked by qh_DUPLICATEridge
 
   notes:
     ridge is newfacet->vertices w/o newskip vertex
     do not allocate memory (need to free hash_table cleanly)
     uses linear hash chains
 
   see also:
     qh_matchduplicates
 
   design:
     for each possible matching facet in qh.hash_table
       if vertices match
         set ismatch, if facets have opposite orientation
         if ismatch and matching facet doesn't have a match
           match the facets by updating their neighbor sets
         else
           indicate a duplicate ridge
           set facet hyperplane for later testing
           add facet to hashtable
           unless the other facet was already a duplicate ridge
             mark both facets with a duplicate ridge
             add other facet (if defined) to hash table
 */
 void qh_matchneighbor(facetT *newfacet, int newskip, int hashsize, int *hashcount) {
   boolT newfound= False;   /* True, if new facet is already in hash chain */
   boolT same, ismatch;
   int hash, scan;
   facetT *facet, *matchfacet;
   int skip, matchskip;
 
   hash= qh_gethash(hashsize, newfacet->vertices, qh hull_dim, 1,
                      SETelem_(newfacet->vertices, newskip));
   trace4((qh ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
           newfacet->id, newskip, hash, *hashcount));
   zinc_(Zhashlookup);
   for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT));
        scan= (++scan >= hashsize ? 0 : scan)) {
     if (facet == newfacet) {
       newfound= True;
       continue;
     }
     zinc_(Zhashtests);
     if (qh_matchvertices(1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
       if (SETelem_(newfacet->vertices, newskip) ==
           SETelem_(facet->vertices, skip)) {
         qh_precision("two facets with the same vertices");
         qh_fprintf(qh ferr, 6106, "qhull precision error: Vertex sets are the same for f%d and f%d.  Can not force output.\n",
           facet->id, newfacet->id);
         qh_errexit2(qh_ERRprec, facet, newfacet);
       }
       ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));
       matchfacet= SETelemt_(facet->neighbors, skip, facetT);
       if (ismatch && !matchfacet) {
         SETelem_(facet->neighbors, skip)= newfacet;
         SETelem_(newfacet->neighbors, newskip)= facet;
         (*hashcount)--;
         trace4((qh ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
            facet->id, skip, newfacet->id, newskip));
         return;
       }
       if (!qh PREmerge && !qh MERGEexact) {
         qh_precision("a ridge with more than two neighbors");
         qh_fprintf(qh ferr, 6107, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue.\n",
                  facet->id, newfacet->id, getid_(matchfacet));
         qh_errexit2(qh_ERRprec, facet, newfacet);
       }
       SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
       newfacet->dupridge= True;
       if (!newfacet->normal)
         qh_setfacetplane(newfacet);
       qh_addhash(newfacet, qh hash_table, hashsize, hash);
       (*hashcount)++;
       if (!facet->normal)
         qh_setfacetplane(facet);
       if (matchfacet != qh_DUPLICATEridge) {
         SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
         facet->dupridge= True;
         if (!facet->normal)
           qh_setfacetplane(facet);
         if (matchfacet) {
           matchskip= qh_setindex(matchfacet->neighbors, facet);
           SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge;
           matchfacet->dupridge= True;
           if (!matchfacet->normal)
             qh_setfacetplane(matchfacet);
           qh_addhash(matchfacet, qh hash_table, hashsize, hash);
           *hashcount += 2;
         }
       }
       trace4((qh ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
            newfacet->id, newskip, facet->id, skip,
            (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),
            ismatch, hash));
       return; /* end of duplicate ridge */
     }
   }
   if (!newfound)
     SETelem_(qh hash_table, scan)= newfacet;  /* same as qh_addhash */
   (*hashcount)++;
   trace4((qh ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
            newfacet->id, newskip, hash));
 } /* matchneighbor */
 
 
 /*---------------------------------
 
   qh_matchnewfacets()
     match newfacets in qh.newfacet_list to their newfacet neighbors
 
   returns:
     qh.newfacet_list with full neighbor sets
       get vertices with nth neighbor by deleting nth vertex
     if qh.PREmerge/MERGEexact or qh.FORCEoutput
       sets facet->flippped if flipped normal (also prevents point partitioning)
     if duplicate ridges and qh.PREmerge/MERGEexact
       sets facet->dupridge
       missing neighbor links identifies extra ridges to be merging (qh_MERGEridge)
 
   notes:
     newfacets already have neighbor[0] (horizon facet)
     assumes qh.hash_table is NULL
     vertex->neighbors has not been updated yet
     do not allocate memory after qh.hash_table (need to free it cleanly)
 
   design:
     delete neighbor sets for all new facets
     initialize a hash table
     for all new facets
       match facet with neighbors
     if unmatched facets (due to duplicate ridges)
       for each new facet with a duplicate ridge
         match it with a facet
     check for flipped facets
 */
 void qh_matchnewfacets(void /* qh.newfacet_list */) {
   int numnew=0, hashcount=0, newskip;
   facetT *newfacet, *neighbor;
   int dim= qh hull_dim, hashsize, neighbor_i, neighbor_n;
   setT *neighbors;
 #ifndef qh_NOtrace
   int facet_i, facet_n, numfree= 0;
   facetT *facet;
 #endif
 
   trace1((qh ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));
   FORALLnew_facets {
     numnew++;
     {  /* inline qh_setzero(newfacet->neighbors, 1, qh hull_dim); */
       neighbors= newfacet->neighbors;
       neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
       memset((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize);
     }
   }
 
   qh_newhashtable(numnew*(qh hull_dim-1)); /* twice what is normally needed,
                                      but every ridge could be DUPLICATEridge */
   hashsize= qh_setsize(qh hash_table);
   FORALLnew_facets {
     for (newskip=1; newskipneighbors, k, facetT);
           if (!neighbor || neighbor == qh_DUPLICATEridge)
             count++;
         }
         if (facet == newfacet)
           break;
       }
       if (count != hashcount) {
         qh_fprintf(qh ferr, 8088, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n",
                  newfacet->id, hashcount, count);
         qh_errexit(qh_ERRqhull, newfacet, NULL);
       }
     }
 #endif  /* end of trap code */
   }
   if (hashcount) {
     FORALLnew_facets {
       if (newfacet->dupridge) {
         FOREACHneighbor_i_(newfacet) {
           if (neighbor == qh_DUPLICATEridge) {
             qh_matchduplicates(newfacet, neighbor_i, hashsize, &hashcount);
                     /* this may report MERGEfacet */
           }
         }
       }
     }
   }
   if (hashcount) {
     qh_fprintf(qh ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
         hashcount);
     qh_printhashtable(qh ferr);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
 #ifndef qh_NOtrace
   if (qh IStracing >= 2) {
     FOREACHfacet_i_(qh hash_table) {
       if (!facet)
         numfree++;
     }
     qh_fprintf(qh ferr, 8089, "qh_matchnewfacets: %d new facets, %d unused hash entries .  hashsize %d\n",
              numnew, numfree, qh_setsize(qh hash_table));
   }
 #endif /* !qh_NOtrace */
   qh_setfree(&qh hash_table);
   if (qh PREmerge || qh MERGEexact) {
     if (qh IStracing >= 4)
       qh_printfacetlist(qh newfacet_list, NULL, qh_ALL);
     FORALLnew_facets {
       if (newfacet->normal)
         qh_checkflipped(newfacet, NULL, qh_ALL);
     }
   }else if (qh FORCEoutput)
     qh_checkflipped_all(qh newfacet_list);  /* prints warnings for flipped */
 } /* matchnewfacets */
 
 
 /*---------------------------------
 
   qh_matchvertices( firstindex, verticesA, skipA, verticesB, skipB, same )
     tests whether vertices match with a single skip
     starts match at firstindex since all new facets have a common vertex
 
   returns:
     true if matched vertices
     skip index for each set
     sets same iff vertices have the same orientation
 
   notes:
     assumes skipA is in A and both sets are the same size
 
   design:
     set up pointers
     scan both sets checking for a match
     test orientation
 */
 boolT qh_matchvertices(int firstindex, setT *verticesA, int skipA,
        setT *verticesB, int *skipB, boolT *same) {
   vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;
 
   elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
   elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
   skipAp= SETelemaddr_(verticesA, skipA, vertexT);
   do if (elemAp != skipAp) {
     while (*elemAp != *elemBp++) {
       if (skipBp)
         return False;
       skipBp= elemBp;  /* one extra like FOREACH */
     }
   }while (*(++elemAp));
   if (!skipBp)
     skipBp= ++elemBp;
   *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB */
   *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */
   trace4((qh ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",
           skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
   return(True);
 } /* matchvertices */
 
 /*---------------------------------
 
   qh_newfacet()
     return a new facet
 
   returns:
     all fields initialized or cleared   (NULL)
     preallocates neighbors set
 */
 facetT *qh_newfacet(void) {
   facetT *facet;
   void **freelistp; /* used !qh_NOmem */
 
   qh_memalloc_((int)sizeof(facetT), freelistp, facet, facetT);
   memset((char *)facet, (size_t)0, sizeof(facetT));
   if (qh facet_id == qh tracefacet_id)
     qh tracefacet= facet;
   facet->id= qh facet_id++;
   facet->neighbors= qh_setnew(qh hull_dim);
 #if !qh_COMPUTEfurthest
   facet->furthestdist= 0.0;
 #endif
 #if qh_MAXoutside
   if (qh FORCEoutput && qh APPROXhull)
     facet->maxoutside= qh MINoutside;
   else
     facet->maxoutside= qh DISTround;
 #endif
   facet->simplicial= True;
   facet->good= True;
   facet->newfacet= True;
   trace4((qh ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));
   return(facet);
 } /* newfacet */
 
 
 /*---------------------------------
 
   qh_newridge()
     return a new ridge
 */
 ridgeT *qh_newridge(void) {
   ridgeT *ridge;
   void **freelistp;   /* used !qh_NOmem */
 
   qh_memalloc_((int)sizeof(ridgeT), freelistp, ridge, ridgeT);
   memset((char *)ridge, (size_t)0, sizeof(ridgeT));
   zinc_(Ztotridges);
   if (qh ridge_id == 0xFFFFFF) {
     qh_fprintf(qh ferr, 7074, "\
 qhull warning: more than %d ridges.  ID field overflows and two ridges\n\
 may have the same identifier.  Otherwise output ok.\n", 0xFFFFFF);
   }
   ridge->id= qh ridge_id++;
   trace4((qh ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));
   return(ridge);
 } /* newridge */
 
 
 /*---------------------------------
 
   qh_pointid(  )
     return id for a point,
     returns -3 if null, -2 if interior, or -1 if not known
 
   alternative code:
     unsigned long id;
     id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;
 
   notes:
     WARN64 -- id truncated to 32-bits, at most 2G points
     NOerrors returned (QhullPoint::id)
     if point not in point array
       the code does a comparison of unrelated pointers.
 */
 int qh_pointid(pointT *point) {
   ptr_intT offset, id;
 
   if (!point)
     return -3;
   else if (point == qh interior_point)
     return -2;
   else if (point >= qh first_point
   && point < qh first_point + qh num_points * qh hull_dim) {
     offset= (ptr_intT)(point - qh first_point);
     id= offset / qh hull_dim;
   }else if ((id= qh_setindex(qh other_points, point)) != -1)
     id += qh num_points;
   else
     return -1;
   return (int)id;
 } /* pointid */
 
 /*---------------------------------
 
   qh_removefacet( facet )
     unlinks facet from qh.facet_list,
 
   returns:
     updates qh.facet_list .newfacet_list .facet_next visible_list
     decrements qh.num_facets
 
   see:
     qh_appendfacet
 */
 void qh_removefacet(facetT *facet) {
   facetT *next= facet->next, *previous= facet->previous;
 
   if (facet == qh newfacet_list)
     qh newfacet_list= next;
   if (facet == qh facet_next)
     qh facet_next= next;
   if (facet == qh visible_list)
     qh visible_list= next;
   if (previous) {
     previous->next= next;
     next->previous= previous;
   }else {  /* 1st facet in qh facet_list */
     qh facet_list= next;
     qh facet_list->previous= NULL;
   }
   qh num_facets--;
   trace4((qh ferr, 4057, "qh_removefacet: remove f%d from facet_list\n", facet->id));
 } /* removefacet */
 
 
 /*---------------------------------
 
   qh_removevertex( vertex )
     unlinks vertex from qh.vertex_list,
 
   returns:
     updates qh.vertex_list .newvertex_list
     decrements qh.num_vertices
 */
 void qh_removevertex(vertexT *vertex) {
   vertexT *next= vertex->next, *previous= vertex->previous;
 
   if (vertex == qh newvertex_list)
     qh newvertex_list= next;
   if (previous) {
     previous->next= next;
     next->previous= previous;
   }else {  /* 1st vertex in qh vertex_list */
     qh vertex_list= vertex->next;
     qh vertex_list->previous= NULL;
   }
   qh num_vertices--;
   trace4((qh ferr, 4058, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));
 } /* removevertex */
 
 
 /*---------------------------------
 
   qh_updatevertices()
     update vertex neighbors and delete interior vertices
 
   returns:
     if qh.VERTEXneighbors, updates neighbors for each vertex
       if qh.newvertex_list,
          removes visible neighbors  from vertex neighbors
       if qh.newfacet_list
          adds new facets to vertex neighbors
     if qh.visible_list
        interior vertices added to qh.del_vertices for later partitioning
 
   design:
     if qh.VERTEXneighbors
       deletes references to visible facets from vertex neighbors
       appends new facets to the neighbor list for each vertex
       checks all vertices of visible facets
         removes visible facets from neighbor lists
         marks unused vertices for deletion
 */
 void qh_updatevertices(void /*qh.newvertex_list, newfacet_list, visible_list*/) {
   facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
   vertexT *vertex, **vertexp;
 
   trace3((qh ferr, 3013, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n"));
   if (qh VERTEXneighbors) {
     FORALLvertex_(qh newvertex_list) {
       FOREACHneighbor_(vertex) {
         if (neighbor->visible)
           SETref_(neighbor)= NULL;
       }
       qh_setcompact(vertex->neighbors);
     }
     FORALLnew_facets {
       FOREACHvertex_(newfacet->vertices)
         qh_setappend(&vertex->neighbors, newfacet);
     }
     FORALLvisible_facets {
       FOREACHvertex_(visible->vertices) {
         if (!vertex->newlist && !vertex->deleted) {
           FOREACHneighbor_(vertex) { /* this can happen under merging */
             if (!neighbor->visible)
               break;
           }
           if (neighbor)
             qh_setdel(vertex->neighbors, visible);
           else {
             vertex->deleted= True;
             qh_setappend(&qh del_vertices, vertex);
             trace2((qh ferr, 2041, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",
                   qh_pointid(vertex->point), vertex->id, visible->id));
           }
         }
       }
     }
   }else {  /* !VERTEXneighbors */
     FORALLvisible_facets {
       FOREACHvertex_(visible->vertices) {
         if (!vertex->newlist && !vertex->deleted) {
           vertex->deleted= True;
           qh_setappend(&qh del_vertices, vertex);
           trace2((qh ferr, 2042, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",
                   qh_pointid(vertex->point), vertex->id, visible->id));
         }
       }
     }
   }
 } /* updatevertices */
 
 
 
diff --git a/src/libqhull/poly.h b/src/libqhull/poly.h
index a13a161..9656821 100644
--- a/src/libqhull/poly.h
+++ b/src/libqhull/poly.h
@@ -1,295 +1,295 @@
 /*
  ---------------------------------
 
    poly.h
    header file for poly.c and poly2.c
 
    see qh-poly.htm, libqhull.h and poly.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/poly.h#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/poly.h#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFpoly
 #define qhDEFpoly 1
 
 #include "libqhull.h"
 
 /*===============   constants ========================== */
 
 /*----------------------------------
 
   ALGORITHMfault
     use as argument to checkconvex() to report errors during buildhull
 */
 #define qh_ALGORITHMfault 0
 
 /*----------------------------------
 
   DATAfault
     use as argument to checkconvex() to report errors during initialhull
 */
 #define qh_DATAfault 1
 
 /*----------------------------------
 
   DUPLICATEridge
     special value for facet->neighbor to indicate a duplicate ridge
 
   notes:
     set by matchneighbor, used by matchmatch and mark_dupridge
 */
 #define qh_DUPLICATEridge (facetT *)1L
 
 /*----------------------------------
 
   MERGEridge       flag in facet
     special value for facet->neighbor to indicate a merged ridge
 
   notes:
     set by matchneighbor, used by matchmatch and mark_dupridge
 */
 #define qh_MERGEridge (facetT *)2L
 
 
 /*============ -structures- ====================*/
 
 /*=========== -macros- =========================*/
 
 /*----------------------------------
 
   FORALLfacet_( facetlist ) { ... }
     assign 'facet' to each facet in facetlist
 
   notes:
     uses 'facetT *facet;'
     assumes last facet is a sentinel
 
   see:
     FORALLfacets
 */
 #define FORALLfacet_( facetlist ) if (facetlist ) for ( facet=( facetlist ); facet && facet->next; facet= facet->next )
 
 /*----------------------------------
 
   FORALLnew_facets { ... }
     assign 'newfacet' to each facet in qh.newfacet_list
 
   notes:
     uses 'facetT *newfacet;'
     at exit, newfacet==NULL
 */
 #define FORALLnew_facets for ( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
 
 /*----------------------------------
 
   FORALLvertex_( vertexlist ) { ... }
     assign 'vertex' to each vertex in vertexlist
 
   notes:
     uses 'vertexT *vertex;'
     at exit, vertex==NULL
 */
 #define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
 
 /*----------------------------------
 
   FORALLvisible_facets { ... }
     assign 'visible' to each visible facet in qh.visible_list
 
   notes:
     uses 'vacetT *visible;'
     at exit, visible==NULL
 */
 #define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)
 
 /*----------------------------------
 
   FORALLsame_( newfacet ) { ... }
     assign 'same' to each facet in newfacet->f.samecycle
 
   notes:
     uses 'facetT *same;'
     stops when it returns to newfacet
 */
 #define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
 
 /*----------------------------------
 
   FORALLsame_cycle_( newfacet ) { ... }
     assign 'same' to each facet in newfacet->f.samecycle
 
   notes:
     uses 'facetT *same;'
     at exit, same == NULL
 */
 #define FORALLsame_cycle_(newfacet) \
      for (same= newfacet->f.samecycle; \
          same; same= (same == newfacet ?  NULL : same->f.samecycle))
 
 /*----------------------------------
 
   FOREACHneighborA_( facet ) { ... }
     assign 'neighborA' to each neighbor in facet->neighbors
 
   FOREACHneighborA_( vertex ) { ... }
     assign 'neighborA' to each neighbor in vertex->neighbors
 
   declare:
     facetT *neighborA, **neighborAp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
 
 /*----------------------------------
 
   FOREACHvisible_( facets ) { ... }
     assign 'visible' to each facet in facets
 
   notes:
     uses 'facetT *facet, *facetp;'
     see FOREACHsetelement_
 */
 #define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
 
 /*----------------------------------
 
   FOREACHnewfacet_( facets ) { ... }
     assign 'newfacet' to each facet in facets
 
   notes:
     uses 'facetT *newfacet, *newfacetp;'
     see FOREACHsetelement_
 */
 #define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
 
 /*----------------------------------
 
   FOREACHvertexA_( vertices ) { ... }
     assign 'vertexA' to each vertex in vertices
 
   notes:
     uses 'vertexT *vertexA, *vertexAp;'
     see FOREACHsetelement_
 */
 #define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
 
 /*----------------------------------
 
   FOREACHvertexreverse12_( vertices ) { ... }
     assign 'vertex' to each vertex in vertices
     reverse order of first two vertices
 
   notes:
     uses 'vertexT *vertex, *vertexp;'
     see FOREACHsetelement_
 */
 #define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
 
 
 /*=============== prototypes poly.c in alphabetical order ================*/
 
 void    qh_appendfacet(facetT *facet);
 void    qh_appendvertex(vertexT *vertex);
 void    qh_attachnewfacets(void /* qh.visible_list, newfacet_list */);
 boolT   qh_checkflipped(facetT *facet, realT *dist, boolT allerror);
 void    qh_delfacet(facetT *facet);
 void    qh_deletevisible(void /*qh.visible_list, qh horizon_list*/);
 setT   *qh_facetintersect(facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
 int     qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem);
 facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
 void    qh_makenewplanes(void /* newfacet_list */);
 facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew);
 facetT *qh_makenew_simplicial(facetT *visible, vertexT *apex, int *numnew);
 void    qh_matchneighbor(facetT *newfacet, int newskip, int hashsize,
                           int *hashcount);
 void    qh_matchnewfacets(void);
 boolT   qh_matchvertices(int firstindex, setT *verticesA, int skipA,
                           setT *verticesB, int *skipB, boolT *same);
 facetT *qh_newfacet(void);
 ridgeT *qh_newridge(void);
 int     qh_pointid(pointT *point);
 void    qh_removefacet(facetT *facet);
 void    qh_removevertex(vertexT *vertex);
 void    qh_updatevertices(void);
 
 
 /*========== -prototypes poly2.c in alphabetical order ===========*/
 
 void    qh_addhash(void* newelem, setT *hashtable, int hashsize, int hash);
 void    qh_check_bestdist(void);
 void    qh_check_maxout(void);
 void    qh_check_output(void);
 void    qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
 void    qh_check_points(void);
 void    qh_checkconvex(facetT *facetlist, int fault);
 void    qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp);
 void    qh_checkflipped_all(facetT *facetlist);
 void    qh_checkpolygon(facetT *facetlist);
 void    qh_checkvertex(vertexT *vertex);
 void    qh_clearcenters(qh_CENTER type);
 void    qh_createsimplex(setT *vertices);
 void    qh_delridge(ridgeT *ridge);
 void    qh_delvertex(vertexT *vertex);
 setT   *qh_facet3vertex(facetT *facet);
 facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
            realT *bestdist, boolT *isoutside);
 facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart);
 facetT *qh_findfacet_all(pointT *point, realT *bestdist, boolT *isoutside,
                           int *numpart);
 int     qh_findgood(facetT *facetlist, int goodhorizon);
 void    qh_findgood_all(facetT *facetlist);
 void    qh_furthestnext(void /* qh.facet_list */);
 void    qh_furthestout(facetT *facet);
 void    qh_infiniteloop(facetT *facet);
 void    qh_initbuild(void);
 void    qh_initialhull(setT *vertices);
 setT   *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints);
 vertexT *qh_isvertex(pointT *point, setT *vertices);
 vertexT *qh_makenewfacets(pointT *point /*horizon_list, visible_list*/);
 void    qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount);
 void    qh_nearcoplanar(void /* qh.facet_list */);
 vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp);
 int     qh_newhashtable(int newsize);
 vertexT *qh_newvertex(pointT *point);
 ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp);
 void    qh_outcoplanar(void /* facet_list */);
 pointT *qh_point(int id);
 void    qh_point_add(setT *set, pointT *point, void *elem);
 setT   *qh_pointfacet(void /*qh.facet_list*/);
 setT   *qh_pointvertex(void /*qh.facet_list*/);
 void    qh_prependfacet(facetT *facet, facetT **facetlist);
 void    qh_printhashtable(FILE *fp);
 void    qh_printlists(void);
 void    qh_resetlists(boolT stats, boolT resetVisible /*qh.newvertex_list newfacet_list visible_list*/);
 void    qh_setvoronoi_all(void);
 void    qh_triangulate(void /*qh.facet_list*/);
 void    qh_triangulate_facet(facetT *facetA, vertexT **first_vertex);
 void    qh_triangulate_link(facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
 void    qh_triangulate_mirror(facetT *facetA, facetT *facetB);
 void    qh_triangulate_null(facetT *facetA);
 void    qh_vertexintersect(setT **vertexsetA,setT *vertexsetB);
 setT   *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB);
 void    qh_vertexneighbors(void /*qh.facet_list*/);
 boolT   qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
 
 
 #endif /* qhDEFpoly */
diff --git a/src/libqhull/poly2.c b/src/libqhull/poly2.c
index ec37ade..4c0da1b 100644
--- a/src/libqhull/poly2.c
+++ b/src/libqhull/poly2.c
@@ -1,3154 +1,3154 @@
 /*
  ---------------------------------
 
    poly2.c
    implements polygons and simplices
 
    see qh-poly.htm, poly.h and libqhull.h
 
    frequently used code is in poly.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/poly2.c#6 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/poly2.c#8 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_a.h"
 
 /*======== functions in alphabetical order ==========*/
 
 /*---------------------------------
 
   qh_addhash( newelem, hashtable, hashsize, hash )
     add newelem to linear hash table at hash if not already there
 */
 void qh_addhash(void* newelem, setT *hashtable, int hashsize, int hash) {
   int scan;
   void *elem;
 
   for (scan= (int)hash; (elem= SETelem_(hashtable, scan));
        scan= (++scan >= hashsize ? 0 : scan)) {
     if (elem == newelem)
       break;
   }
   /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
   if (!elem)
     SETelem_(hashtable, scan)= newelem;
 } /* addhash */
 
 /*---------------------------------
 
   qh_check_bestdist()
     check that all points are within max_outside of the nearest facet
     if qh.ONLYgood,
       ignores !good facets
 
   see:
     qh_check_maxout(), qh_outerinner()
 
   notes:
     only called from qh_check_points()
       seldom used since qh.MERGING is almost always set
     if notverified>0 at end of routine
       some points were well inside the hull.  If the hull contains
       a lens-shaped component, these points were not verified.  Use
       options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
 
   design:
     determine facet for each point (if any)
     for each point
       start with the assigned facet or with the first facet
       find the best facet for the point and check all coplanar facets
       error if point is outside of facet
 */
 void qh_check_bestdist(void) {
   boolT waserror= False, unassigned;
   facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
   facetT *facetlist;
   realT dist, maxoutside, maxdist= -REALmax;
   pointT *point;
   int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
   setT *facets;
 
   trace1((qh ferr, 1020, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
       qh facet_list->id));
   maxoutside= qh_maxouter();
   maxoutside += qh DISTround;
   /* one more qh.DISTround for check computation */
   trace1((qh ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
   facets= qh_pointfacet(/*qh.facet_list*/);
   if (!qh_QUICKhelp && qh PRINTprecision)
     qh_fprintf(qh ferr, 8091, "\n\
 qhull output completed.  Verifying that %d points are\n\
 below %2.2g of the nearest %sfacet.\n",
              qh_setsize(facets), maxoutside, (qh ONLYgood ?  "good " : ""));
   FOREACHfacet_i_(facets) {  /* for each point with facet assignment */
     if (facet)
       unassigned= False;
     else {
       unassigned= True;
       facet= qh facet_list;
     }
     point= qh_point(facet_i);
     if (point == qh GOODpointp)
       continue;
     qh_distplane(point, facet, &dist);
     numpart++;
     bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
     /* occurs after statistics reported */
     maximize_(maxdist, dist);
     if (dist > maxoutside) {
       if (qh ONLYgood && !bestfacet->good
           && !((bestfacet= qh_findgooddist(point, bestfacet, &dist, &facetlist))
                && dist > maxoutside))
         notgood++;
       else {
         waserror= True;
         qh_fprintf(qh ferr, 6109, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
                 facet_i, bestfacet->id, dist, maxoutside);
         if (errfacet1 != bestfacet) {
           errfacet2= errfacet1;
           errfacet1= bestfacet;
         }
       }
     }else if (unassigned && dist < -qh MAXcoplanar)
       notverified++;
   }
   qh_settempfree(&facets);
   if (notverified && !qh DELAUNAY && !qh_QUICKhelp && qh PRINTprecision)
     qh_fprintf(qh ferr, 8092, "\n%d points were well inside the hull.  If the hull contains\n\
 a lens-shaped component, these points were not verified.  Use\n\
 options 'Qci Tv' to verify all points.\n", notverified);
   if (maxdist > qh outside_err) {
     qh_fprintf(qh ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
               maxdist, qh outside_err);
     qh_errexit2(qh_ERRprec, errfacet1, errfacet2);
   }else if (waserror && qh outside_err > REALmax/2)
     qh_errexit2(qh_ERRprec, errfacet1, errfacet2);
   /* else if waserror, the error was logged to qh.ferr but does not effect the output */
   trace0((qh ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
 } /* check_bestdist */
 
 /*---------------------------------
 
   qh_check_maxout()
     updates qh.max_outside by checking all points against bestfacet
     if qh.ONLYgood, ignores !good facets
 
   returns:
     updates facet->maxoutside via qh_findbesthorizon()
     sets qh.maxoutdone
     if printing qh.min_vertex (qh_outerinner),
       it is updated to the current vertices
     removes inside/coplanar points from coplanarset as needed
 
   notes:
     defines coplanar as min_vertex instead of MAXcoplanar
     may not need to check near-inside points because of qh.MAXcoplanar
       and qh.KEEPnearinside (before it was -DISTround)
 
   see also:
     qh_check_bestdist()
 
   design:
     if qh.min_vertex is needed
       for all neighbors of all vertices
         test distance from vertex to neighbor
     determine facet for each point (if any)
     for each point with an assigned facet
       find the best facet for the point and check all coplanar facets
         (updates outer planes)
     remove near-inside points from coplanar sets
 */
 #ifndef qh_NOmerge
 void qh_check_maxout(void) {
   facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;
   realT dist, maxoutside, minvertex, old_maxoutside;
   pointT *point;
   int numpart= 0, facet_i, facet_n, notgood= 0;
   setT *facets, *vertices;
   vertexT *vertex;
 
   trace1((qh ferr, 1022, "qh_check_maxout: check and update maxoutside for each facet.\n"));
   maxoutside= minvertex= 0;
   if (qh VERTEXneighbors
   && (qh PRINTsummary || qh KEEPinside || qh KEEPcoplanar
         || qh TRACElevel || qh PRINTstatistics
         || qh PRINTout[0] == qh_PRINTsummary || qh PRINTout[0] == qh_PRINTnone)) {
     trace1((qh ferr, 1023, "qh_check_maxout: determine actual maxoutside and minvertex\n"));
     vertices= qh_pointvertex(/*qh.facet_list*/);
     FORALLvertices {
       FOREACHneighbor_(vertex) {
         zinc_(Zdistvertex);  /* distance also computed by main loop below */
         qh_distplane(vertex->point, neighbor, &dist);
         minimize_(minvertex, dist);
         if (-dist > qh TRACEdist || dist > qh TRACEdist
         || neighbor == qh tracefacet || vertex == qh tracevertex)
           qh_fprintf(qh ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d\n",
                     qh_pointid(vertex->point), vertex->id, dist, neighbor->id);
       }
     }
     if (qh MERGING) {
       wmin_(Wminvertex, qh min_vertex);
     }
     qh min_vertex= minvertex;
     qh_settempfree(&vertices);
   }
   facets= qh_pointfacet(/*qh.facet_list*/);
   do {
     old_maxoutside= fmax_(qh max_outside, maxoutside);
     FOREACHfacet_i_(facets) {     /* for each point with facet assignment */
       if (facet) {
         point= qh_point(facet_i);
         if (point == qh GOODpointp)
           continue;
         zzinc_(Ztotcheck);
         qh_distplane(point, facet, &dist);
         numpart++;
         bestfacet= qh_findbesthorizon(qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
         if (bestfacet && dist > maxoutside) {
           if (qh ONLYgood && !bestfacet->good
           && !((bestfacet= qh_findgooddist(point, bestfacet, &dist, &facetlist))
                && dist > maxoutside))
             notgood++;
           else
             maxoutside= dist;
         }
         if (dist > qh TRACEdist || (bestfacet && bestfacet == qh tracefacet))
           qh_fprintf(qh ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",
                      qh_pointid(point), dist, bestfacet->id);
       }
     }
   }while
     (maxoutside > 2*old_maxoutside);
     /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid
           e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */
   zzadd_(Zcheckpart, numpart);
   qh_settempfree(&facets);
   wval_(Wmaxout)= maxoutside - qh max_outside;
   wmax_(Wmaxoutside, qh max_outside);
   qh max_outside= maxoutside;
   qh_nearcoplanar(/*qh.facet_list*/);
   qh maxoutdone= True;
   trace1((qh ferr, 1024, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",
        maxoutside, qh min_vertex, notgood));
 } /* check_maxout */
 #else /* qh_NOmerge */
 void qh_check_maxout(void) {
 }
 #endif
 
 /*---------------------------------
 
   qh_check_output()
     performs the checks at the end of qhull algorithm
     Maybe called after voronoi output.  Will recompute otherwise centrums are Voronoi centers instead
 */
 void qh_check_output(void) {
   int i;
 
   if (qh STOPcone)
     return;
   if (qh VERIFYoutput | qh IStracing | qh CHECKfrequently) {
     qh_checkpolygon(qh facet_list);
     qh_checkflipped_all(qh facet_list);
     qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
   }else if (!qh MERGING && qh_newstats(qhstat precision, &i)) {
     qh_checkflipped_all(qh facet_list);
     qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
   }
 } /* check_output */
 
 
 
 /*---------------------------------
 
   qh_check_point( point, facet, maxoutside, maxdist, errfacet1, errfacet2 )
     check that point is less than maxoutside from facet
 */
 void qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {
   realT dist;
 
   /* occurs after statistics reported */
   qh_distplane(point, facet, &dist);
   if (dist > *maxoutside) {
     if (*errfacet1 != facet) {
       *errfacet2= *errfacet1;
       *errfacet1= facet;
     }
     qh_fprintf(qh ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
               qh_pointid(point), facet->id, dist, *maxoutside);
   }
   maximize_(*maxdist, dist);
 } /* qh_check_point */
 
 
 /*---------------------------------
 
   qh_check_points()
     checks that all points are inside all facets
 
   notes:
     if many points and qh_check_maxout not called (i.e., !qh.MERGING),
        calls qh_findbesthorizon (seldom done).
     ignores flipped facets
     maxoutside includes 2 qh.DISTrounds
       one qh.DISTround for the computed distances in qh_check_points
     qh_printafacet and qh_printsummary needs only one qh.DISTround
     the computation for qh.VERIFYdirect does not account for qh.other_points
 
   design:
     if many points
       use qh_check_bestdist()
     else
       for all facets
         for all points
           check that point is inside facet
 */
 void qh_check_points(void) {
   facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
   realT total, maxoutside, maxdist= -REALmax;
   pointT *point, **pointp, *pointtemp;
   boolT testouter;
 
   maxoutside= qh_maxouter();
   maxoutside += qh DISTround;
   /* one more qh.DISTround for check computation */
   trace1((qh ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",
           maxoutside));
   if (qh num_good)   /* miss counts other_points and !good facets */
      total= (float)qh num_good * (float)qh num_points;
   else
      total= (float)qh num_facets * (float)qh num_points;
   if (total >= qh_VERIFYdirect && !qh maxoutdone) {
     if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING)
       qh_fprintf(qh ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').\n\
 Verify may report that a point is outside of a facet.\n");
     qh_check_bestdist();
   }else {
     if (qh_MAXoutside && qh maxoutdone)
       testouter= True;
     else
       testouter= False;
     if (!qh_QUICKhelp) {
       if (qh MERGEexact)
         qh_fprintf(qh ferr, 7076, "qhull input warning: exact merge ('Qx').  Verify may report that a point\n\
 is outside of a facet.  See qh-optq.htm#Qx\n");
       else if (qh SKIPcheckmax || qh NOnearinside)
         qh_fprintf(qh ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of\n\
 near-inside points ('Q8').  Verify may report that a point is outside\n\
 of a facet.\n");
     }
     if (qh PRINTprecision) {
       if (testouter)
         qh_fprintf(qh ferr, 8098, "\n\
 Output completed.  Verifying that all points are below outer planes of\n\
 all %sfacets.  Will make %2.0f distance computations.\n",
               (qh ONLYgood ?  "good " : ""), total);
       else
         qh_fprintf(qh ferr, 8099, "\n\
 Output completed.  Verifying that all points are below %2.2g of\n\
 all %sfacets.  Will make %2.0f distance computations.\n",
               maxoutside, (qh ONLYgood ?  "good " : ""), total);
     }
     FORALLfacets {
       if (!facet->good && qh ONLYgood)
         continue;
       if (facet->flipped)
         continue;
       if (!facet->normal) {
         qh_fprintf(qh ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
         continue;
       }
       if (testouter) {
 #if qh_MAXoutside
         maxoutside= facet->maxoutside + 2* qh DISTround;
         /* one DISTround to actual point and another to computed point */
 #endif
       }
       FORALLpoints {
         if (point != qh GOODpointp)
           qh_check_point(point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
       }
       FOREACHpoint_(qh other_points) {
         if (point != qh GOODpointp)
           qh_check_point(point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
       }
     }
     if (maxdist > qh outside_err) {
       qh_fprintf(qh ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
                 maxdist, qh outside_err );
       qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
     }else if (errfacet1 && qh outside_err > REALmax/2)
         qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
     /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */
     trace0((qh ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));
   }
 } /* check_points */
 
 
 /*---------------------------------
 
   qh_checkconvex( facetlist, fault )
     check that each ridge in facetlist is convex
     fault = qh_DATAfault if reporting errors
           = qh_ALGORITHMfault otherwise
 
   returns:
     counts Zconcaveridges and Zcoplanarridges
     errors if concaveridge or if merging an coplanar ridge
 
   note:
     if not merging,
       tests vertices for neighboring simplicial facets
     else if ZEROcentrum,
       tests vertices for neighboring simplicial   facets
     else
       tests centrums of neighboring facets
 
   design:
     for all facets
       report flipped facets
       if ZEROcentrum and simplicial neighbors
         test vertices for neighboring simplicial facets
       else
         test centrum against all neighbors
 */
 void qh_checkconvex(facetT *facetlist, int fault) {
   facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
   vertexT *vertex;
   realT dist;
   pointT *centrum;
   boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;
   int neighbor_i;
 
   trace1((qh ferr, 1026, "qh_checkconvex: check all ridges are convex\n"));
   if (!qh RERUN) {
     zzval_(Zconcaveridges)= 0;
     zzval_(Zcoplanarridges)= 0;
   }
   FORALLfacet_(facetlist) {
     if (facet->flipped) {
       qh_precision("flipped facet");
       qh_fprintf(qh ferr, 6113, "qhull precision error: f%d is flipped(interior point is outside)\n",
                facet->id);
       errfacet1= facet;
       waserror= True;
       continue;
     }
     if (qh MERGING && (!qh ZEROcentrum || !facet->simplicial || facet->tricoplanar))
       allsimplicial= False;
     else {
       allsimplicial= True;
       neighbor_i= 0;
       FOREACHneighbor_(facet) {
         vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
         if (!neighbor->simplicial || neighbor->tricoplanar) {
           allsimplicial= False;
           continue;
         }
         qh_distplane(vertex->point, neighbor, &dist);
         if (dist > -qh DISTround) {
           if (fault == qh_DATAfault) {
             qh_precision("coplanar or concave ridge");
             qh_fprintf(qh ferr, 6114, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);
             qh_errexit(qh_ERRsingular, NULL, NULL);
           }
           if (dist > qh DISTround) {
             zzinc_(Zconcaveridges);
             qh_precision("concave ridge");
             qh_fprintf(qh ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above\n",
               facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
             errfacet1= facet;
             errfacet2= neighbor;
             waserror= True;
           }else if (qh ZEROcentrum) {
             if (dist > 0) {     /* qh_checkzero checks that dist < - qh DISTround */
               zzinc_(Zcoplanarridges);
               qh_precision("coplanar ridge");
               qh_fprintf(qh ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above\n",
                 facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
               errfacet1= facet;
               errfacet2= neighbor;
               waserror= True;
             }
           }else {
             zzinc_(Zcoplanarridges);
             qh_precision("coplanar ridge");
             trace0((qh ferr, 22, "qhull precision error: f%d may be coplanar to f%d, since p%d(v%d) is within %6.4g during p%d\n",
               facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, qh furthest_id));
           }
         }
       }
     }
     if (!allsimplicial) {
       if (qh CENTERtype == qh_AScentrum) {
         if (!facet->center)
           facet->center= qh_getcentrum(facet);
         centrum= facet->center;
       }else {
         if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {
            centrum_warning= True;
            qh_fprintf(qh ferr, 7062, "qhull warning: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
         }
         centrum= qh_getcentrum(facet);
         tempcentrum= True;
       }
       FOREACHneighbor_(facet) {
         if (qh ZEROcentrum && facet->simplicial && neighbor->simplicial)
           continue;
         if (facet->tricoplanar || neighbor->tricoplanar)
           continue;
         zzinc_(Zdistconvex);
         qh_distplane(centrum, neighbor, &dist);
         if (dist > qh DISTround) {
           zzinc_(Zconcaveridges);
           qh_precision("concave ridge");
           qh_fprintf(qh ferr, 6117, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
             facet->id, neighbor->id, facet->id, dist, neighbor->id);
           errfacet1= facet;
           errfacet2= neighbor;
           waserror= True;
         }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
                                      can test against centrum radius instead */
           zzinc_(Zcoplanarridges);
           qh_precision("coplanar ridge");
           qh_fprintf(qh ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
             facet->id, neighbor->id, facet->id, dist, neighbor->id);
           errfacet1= facet;
           errfacet2= neighbor;
           waserror= True;
         }
       }
       if (tempcentrum)
         qh_memfree(centrum, qh normal_size);
     }
   }
   if (waserror && !qh FORCEoutput)
     qh_errexit2(qh_ERRprec, errfacet1, errfacet2);
 } /* checkconvex */
 
 
 /*---------------------------------
 
   qh_checkfacet( facet, newmerge, waserror )
     checks for consistency errors in facet
     newmerge set if from merge.c
 
   returns:
     sets waserror if any error occurs
 
   checks:
     vertex ids are inverse sorted
     unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
     if non-simplicial, at least as many ridges as neighbors
     neighbors are not duplicated
     ridges are not duplicated
     in 3-d, ridges=verticies
     (qh.hull_dim-1) ridge vertices
     neighbors are reciprocated
     ridge neighbors are facet neighbors and a ridge for every neighbor
     simplicial neighbors match facetintersect
     vertex intersection matches vertices of common ridges
     vertex neighbors and facet vertices agree
     all ridges have distinct vertex sets
 
   notes:
     uses neighbor->seen
 
   design:
     check sets
     check vertices
     check sizes of neighbors and vertices
     check for qh_MERGEridge and qh_DUPLICATEridge flags
     check neighbor set
     check ridge set
     check ridges, neighbors, and vertices
 */
 void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp) {
   facetT *neighbor, **neighborp, *errother=NULL;
   ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
   vertexT *vertex, **vertexp;
   unsigned previousid= INT_MAX;
   int numneighbors, numvertices, numridges=0, numRvertices=0;
   boolT waserror= False;
   int skipA, skipB, ridge_i, ridge_n, i;
   setT *intersection;
 
   if (facet->visible) {
     qh_fprintf(qh ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",
       facet->id);
     qh_errexit(qh_ERRqhull, facet, NULL);
   }
   if (!facet->normal) {
     qh_fprintf(qh ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have  a normal\n",
       facet->id);
     waserror= True;
   }
   qh_setcheck(facet->vertices, "vertices for f", facet->id);
   qh_setcheck(facet->ridges, "ridges for f", facet->id);
   qh_setcheck(facet->outsideset, "outsideset for f", facet->id);
   qh_setcheck(facet->coplanarset, "coplanarset for f", facet->id);
   qh_setcheck(facet->neighbors, "neighbors for f", facet->id);
   FOREACHvertex_(facet->vertices) {
     if (vertex->deleted) {
       qh_fprintf(qh ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
       qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex);
       waserror= True;
     }
     if (vertex->id >= previousid) {
       qh_fprintf(qh ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
       waserror= True;
       break;
     }
     previousid= vertex->id;
   }
   numneighbors= qh_setsize(facet->neighbors);
   numvertices= qh_setsize(facet->vertices);
   numridges= qh_setsize(facet->ridges);
   if (facet->simplicial) {
     if (numvertices+numneighbors != 2*qh hull_dim
     && !facet->degenerate && !facet->redundant) {
       qh_fprintf(qh ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n",
                 facet->id, numvertices, numneighbors);
       qh_setprint(qh ferr, "", facet->neighbors);
       waserror= True;
     }
   }else { /* non-simplicial */
     if (!newmerge
     &&(numvertices < qh hull_dim || numneighbors < qh hull_dim)
     && !facet->degenerate && !facet->redundant) {
       qh_fprintf(qh ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n",
          facet->id, numvertices, numneighbors);
        waserror= True;
     }
     /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
     if (numridges < numneighbors
     ||(qh hull_dim == 3 && numvertices > numridges && !qh NEWfacets)
     ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
       if (!facet->degenerate && !facet->redundant) {
         qh_fprintf(qh ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",
             facet->id, numridges, numneighbors, numvertices);
         waserror= True;
       }
     }
   }
   FOREACHneighbor_(facet) {
     if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
       qh_fprintf(qh ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);
       qh_errexit(qh_ERRqhull, facet, NULL);
     }
     neighbor->seen= True;
   }
   FOREACHneighbor_(facet) {
     if (!qh_setin(neighbor->neighbors, facet)) {
       qh_fprintf(qh ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
               facet->id, neighbor->id, neighbor->id, facet->id);
       errother= neighbor;
       waserror= True;
     }
     if (!neighbor->seen) {
       qh_fprintf(qh ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
               facet->id, neighbor->id);
       errother= neighbor;
       waserror= True;
     }
     neighbor->seen= False;
   }
   FOREACHridge_(facet->ridges) {
     qh_setcheck(ridge->vertices, "vertices for r", ridge->id);
     ridge->seen= False;
   }
   FOREACHridge_(facet->ridges) {
     if (ridge->seen) {
       qh_fprintf(qh ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
               facet->id, ridge->id);
       errridge= ridge;
       waserror= True;
     }
     ridge->seen= True;
     numRvertices= qh_setsize(ridge->vertices);
     if (numRvertices != qh hull_dim - 1) {
       qh_fprintf(qh ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",
                 ridge->top->id, ridge->bottom->id, numRvertices);
       errridge= ridge;
       waserror= True;
     }
     neighbor= otherfacet_(ridge, facet);
     neighbor->seen= True;
     if (!qh_setin(facet->neighbors, neighbor)) {
       qh_fprintf(qh ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
            facet->id, neighbor->id, ridge->id);
       errridge= ridge;
       waserror= True;
     }
   }
   if (!facet->simplicial) {
     FOREACHneighbor_(facet) {
       if (!neighbor->seen) {
         qh_fprintf(qh ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
               facet->id, neighbor->id);
         errother= neighbor;
         waserror= True;
       }
       intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices);
       qh_settemppush(intersection);
       FOREACHvertex_(facet->vertices) {
         vertex->seen= False;
         vertex->seen2= False;
       }
       FOREACHvertex_(intersection)
         vertex->seen= True;
       FOREACHridge_(facet->ridges) {
         if (neighbor != otherfacet_(ridge, facet))
             continue;
         FOREACHvertex_(ridge->vertices) {
           if (!vertex->seen) {
             qh_fprintf(qh ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
                   vertex->id, ridge->id, facet->id, neighbor->id);
             qh_errexit(qh_ERRqhull, facet, ridge);
           }
           vertex->seen2= True;
         }
       }
       if (!newmerge) {
         FOREACHvertex_(intersection) {
           if (!vertex->seen2) {
             if (qh IStracing >=3 || !qh MERGING) {
               qh_fprintf(qh ferr, 6134, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\
  not in a ridge.  This is ok under merging.  Last point was p%d\n",
                      vertex->id, facet->id, neighbor->id, qh furthest_id);
               if (!qh FORCEoutput && !qh MERGING) {
                 qh_errprint("ERRONEOUS", facet, neighbor, NULL, vertex);
                 if (!qh MERGING)
                   qh_errexit(qh_ERRqhull, NULL, NULL);
               }
             }
           }
         }
       }
       qh_settempfree(&intersection);
     }
   }else { /* simplicial */
     FOREACHneighbor_(facet) {
       if (neighbor->simplicial) {
         skipA= SETindex_(facet->neighbors, neighbor);
         skipB= qh_setindex(neighbor->neighbors, facet);
         if (!qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {
           qh_fprintf(qh ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
                    facet->id, skipA, neighbor->id, skipB);
           errother= neighbor;
           waserror= True;
         }
       }
     }
   }
   if (qh hull_dim < 5 && (qh IStracing > 2 || qh CHECKfrequently)) {
     FOREACHridge_i_(facet->ridges) {           /* expensive */
       for (i=ridge_i+1; i < ridge_n; i++) {
         ridge2= SETelemt_(facet->ridges, i, ridgeT);
         if (qh_setequal(ridge->vertices, ridge2->vertices)) {
           qh_fprintf(qh ferr, 6227, "Qhull internal error (qh_checkfacet): ridges r%d and r%d have the same vertices\n",
                   ridge->id, ridge2->id);
           errridge= ridge;
           waserror= True;
         }
       }
     }
   }
   if (waserror) {
     qh_errprint("ERRONEOUS", facet, errother, errridge, NULL);
     *waserrorp= True;
   }
 } /* checkfacet */
 
 
 /*---------------------------------
 
   qh_checkflipped_all( facetlist )
     checks orientation of facets in list against interior point
 */
 void qh_checkflipped_all(facetT *facetlist) {
   facetT *facet;
   boolT waserror= False;
   realT dist;
 
   if (facetlist == qh facet_list)
     zzval_(Zflippedfacets)= 0;
   FORALLfacet_(facetlist) {
     if (facet->normal && !qh_checkflipped(facet, &dist, !qh_ALL)) {
       qh_fprintf(qh ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
               facet->id, dist);
       if (!qh FORCEoutput) {
         qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL);
         waserror= True;
       }
     }
   }
   if (waserror) {
     qh_fprintf(qh ferr, 8101, "\n\
 A flipped facet occurs when its distance to the interior point is\n\
 greater than %2.2g, the maximum roundoff error.\n", -qh DISTround);
     qh_errexit(qh_ERRprec, NULL, NULL);
   }
 } /* checkflipped_all */
 
 /*---------------------------------
 
   qh_checkpolygon( facetlist )
     checks the correctness of the structure
 
   notes:
     call with either qh.facet_list or qh.newfacet_list
     checks num_facets and num_vertices if qh.facet_list
 
   design:
     for each facet
       checks facet and outside set
     initializes vertexlist
     for each facet
       checks vertex set
     if checking all facets(qh.facetlist)
       check facet count
       if qh.VERTEXneighbors
         check vertex neighbors and count
       check vertex count
 */
 void qh_checkpolygon(facetT *facetlist) {
   facetT *facet;
   vertexT *vertex, **vertexp, *vertexlist;
   int numfacets= 0, numvertices= 0, numridges= 0;
   int totvneighbors= 0, totvertices= 0;
   boolT waserror= False, nextseen= False, visibleseen= False;
 
   trace1((qh ferr, 1027, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));
   if (facetlist != qh facet_list || qh ONLYgood)
     nextseen= True;
   FORALLfacet_(facetlist) {
     if (facet == qh visible_list)
       visibleseen= True;
     if (!facet->visible) {
       if (!nextseen) {
         if (facet == qh facet_next)
           nextseen= True;
         else if (qh_setsize(facet->outsideset)) {
           if (!qh NARROWhull
 #if !qh_COMPUTEfurthest
                || facet->furthestdist >= qh MINoutside
 #endif
                         ) {
             qh_fprintf(qh ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh facet_next\n",
                      facet->id);
             qh_errexit(qh_ERRqhull, facet, NULL);
           }
         }
       }
       numfacets++;
       qh_checkfacet(facet, False, &waserror);
     }
   }
   if (qh visible_list && !visibleseen && facetlist == qh facet_list) {
     qh_fprintf(qh ferr, 6138, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh visible_list->id);
     qh_printlists();
     qh_errexit(qh_ERRqhull, qh visible_list, NULL);
   }
   if (facetlist == qh facet_list)
     vertexlist= qh vertex_list;
   else if (facetlist == qh newfacet_list)
     vertexlist= qh newvertex_list;
   else
     vertexlist= NULL;
   FORALLvertex_(vertexlist) {
     vertex->seen= False;
     vertex->visitid= 0;
   }
   FORALLfacet_(facetlist) {
     if (facet->visible)
       continue;
     if (facet->simplicial)
       numridges += qh hull_dim;
     else
       numridges += qh_setsize(facet->ridges);
     FOREACHvertex_(facet->vertices) {
       vertex->visitid++;
       if (!vertex->seen) {
         vertex->seen= True;
         numvertices++;
         if (qh_pointid(vertex->point) == -1) {
           qh_fprintf(qh ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
                    vertex->point, vertex->id, qh first_point);
           waserror= True;
         }
       }
     }
   }
   qh vertex_visit += (unsigned int)numfacets;
   if (facetlist == qh facet_list) {
     if (numfacets != qh num_facets - qh num_visible) {
       qh_fprintf(qh ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
               numfacets, qh num_facets, qh num_visible);
       waserror= True;
     }
     qh vertex_visit++;
     if (qh VERTEXneighbors) {
       FORALLvertices {
         qh_setcheck(vertex->neighbors, "neighbors for v", vertex->id);
         if (vertex->deleted)
           continue;
         totvneighbors += qh_setsize(vertex->neighbors);
       }
       FORALLfacet_(facetlist)
         totvertices += qh_setsize(facet->vertices);
       if (totvneighbors != totvertices) {
         qh_fprintf(qh ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent.  Totvneighbors %d, totvertices %d\n",
                 totvneighbors, totvertices);
         waserror= True;
       }
     }
     if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) {
       qh_fprintf(qh ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
               numvertices, qh num_vertices - qh_setsize(qh del_vertices));
       waserror= True;
     }
     if (qh hull_dim == 2 && numvertices != numfacets) {
       qh_fprintf(qh ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
         numvertices, numfacets);
       waserror= True;
     }
     if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
       qh_fprintf(qh ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\
         A vertex appears twice in a edge list.  May occur during merging.",
         numvertices, numfacets, numridges/2);
       /* occurs if lots of merging and a vertex ends up twice in an edge list.  e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */
     }
   }
   if (waserror)
     qh_errexit(qh_ERRqhull, NULL, NULL);
 } /* checkpolygon */
 
 
 /*---------------------------------
 
   qh_checkvertex( vertex )
     check vertex for consistency
     checks vertex->neighbors
 
   notes:
     neighbors checked efficiently in checkpolygon
 */
 void qh_checkvertex(vertexT *vertex) {
   boolT waserror= False;
   facetT *neighbor, **neighborp, *errfacet=NULL;
 
   if (qh_pointid(vertex->point) == -1) {
     qh_fprintf(qh ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
     waserror= True;
   }
   if (vertex->id >= qh vertex_id) {
     qh_fprintf(qh ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);
     waserror= True;
   }
   if (!waserror && !vertex->deleted) {
     if (qh_setsize(vertex->neighbors)) {
       FOREACHneighbor_(vertex) {
         if (!qh_setin(neighbor->vertices, vertex)) {
           qh_fprintf(qh ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
           errfacet= neighbor;
           waserror= True;
         }
       }
     }
   }
   if (waserror) {
     qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex);
     qh_errexit(qh_ERRqhull, errfacet, NULL);
   }
 } /* checkvertex */
 
 /*---------------------------------
 
   qh_clearcenters( type )
     clear old data from facet->center
 
   notes:
     sets new centertype
     nop if CENTERtype is the same
 */
 void qh_clearcenters(qh_CENTER type) {
   facetT *facet;
 
   if (qh CENTERtype != type) {
     FORALLfacets {
       if (facet->tricoplanar && !facet->keepcentrum)
           facet->center= NULL;
       else if (qh CENTERtype == qh_ASvoronoi){
         if (facet->center) {
           qh_memfree(facet->center, qh center_size);
           facet->center= NULL;
         }
       }else /* qh.CENTERtype == qh_AScentrum */ {
         if (facet->center) {
           qh_memfree(facet->center, qh normal_size);
           facet->center= NULL;
         }
       }
     }
     qh CENTERtype= type;
   }
   trace2((qh ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));
 } /* clearcenters */
 
 /*---------------------------------
 
   qh_createsimplex( vertices )
     creates a simplex from a set of vertices
 
   returns:
     initializes qh.facet_list to the simplex
     initializes qh.newfacet_list, .facet_tail
     initializes qh.vertex_list, .newvertex_list, .vertex_tail
 
   design:
     initializes lists
     for each vertex
       create a new facet
     for each new facet
       create its neighbor set
 */
 void qh_createsimplex(setT *vertices) {
   facetT *facet= NULL, *newfacet;
   boolT toporient= True;
   int vertex_i, vertex_n, nth;
   setT *newfacets= qh_settemp(qh hull_dim+1);
   vertexT *vertex;
 
   qh facet_list= qh newfacet_list= qh facet_tail= qh_newfacet();
   qh num_facets= qh num_vertices= qh num_visible= 0;
   qh vertex_list= qh newvertex_list= qh vertex_tail= qh_newvertex(NULL);
   FOREACHvertex_i_(vertices) {
     newfacet= qh_newfacet();
     newfacet->vertices= qh_setnew_delnthsorted(vertices, vertex_n,
                                                 vertex_i, 0);
     newfacet->toporient= (unsigned char)toporient;
     qh_appendfacet(newfacet);
     newfacet->newfacet= True;
     qh_appendvertex(vertex);
     qh_setappend(&newfacets, newfacet);
     toporient ^= True;
   }
   FORALLnew_facets {
     nth= 0;
     FORALLfacet_(qh newfacet_list) {
       if (facet != newfacet)
         SETelem_(newfacet->neighbors, nth++)= facet;
     }
     qh_settruncate(newfacet->neighbors, qh hull_dim);
   }
   qh_settempfree(&newfacets);
   trace1((qh ferr, 1028, "qh_createsimplex: created simplex\n"));
 } /* createsimplex */
 
 /*---------------------------------
 
   qh_delridge( ridge )
     deletes ridge from data structures it belongs to
     frees up its memory
 
   notes:
     in merge.c, caller sets vertex->delridge for each vertex
     ridges also freed in qh_freeqhull
 */
 void qh_delridge(ridgeT *ridge) {
   void **freelistp; /* used !qh_NOmem */
 
   qh_setdel(ridge->top->ridges, ridge);
   qh_setdel(ridge->bottom->ridges, ridge);
   qh_setfree(&(ridge->vertices));
   qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp);
 } /* delridge */
 
 
 /*---------------------------------
 
   qh_delvertex( vertex )
     deletes a vertex and frees its memory
 
   notes:
     assumes vertex->adjacencies have been updated if needed
     unlinks from vertex_list
 */
 void qh_delvertex(vertexT *vertex) {
 
   if (vertex == qh tracevertex)
     qh tracevertex= NULL;
   qh_removevertex(vertex);
   qh_setfree(&vertex->neighbors);
   qh_memfree(vertex, (int)sizeof(vertexT));
 } /* delvertex */
 
 
 /*---------------------------------
 
   qh_facet3vertex(  )
     return temporary set of 3-d vertices in qh_ORIENTclock order
 
   design:
     if simplicial facet
       build set from facet->vertices with facet->toporient
     else
       for each ridge in order
         build set from ridge's vertices
 */
 setT *qh_facet3vertex(facetT *facet) {
   ridgeT *ridge, *firstridge;
   vertexT *vertex;
   int cntvertices, cntprojected=0;
   setT *vertices;
 
   cntvertices= qh_setsize(facet->vertices);
   vertices= qh_settemp(cntvertices);
   if (facet->simplicial) {
     if (cntvertices != 3) {
       qh_fprintf(qh ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",
                   cntvertices, facet->id);
       qh_errexit(qh_ERRqhull, facet, NULL);
     }
     qh_setappend(&vertices, SETfirst_(facet->vertices));
     if (facet->toporient ^ qh_ORIENTclock)
       qh_setappend(&vertices, SETsecond_(facet->vertices));
     else
       qh_setaddnth(&vertices, 0, SETsecond_(facet->vertices));
     qh_setappend(&vertices, SETelem_(facet->vertices, 2));
   }else {
     ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
     while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {
       qh_setappend(&vertices, vertex);
       if (++cntprojected > cntvertices || ridge == firstridge)
         break;
     }
     if (!ridge || cntprojected != cntvertices) {
       qh_fprintf(qh ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n",
                   facet->id, cntprojected);
       qh_errexit(qh_ERRqhull, facet, ridge);
     }
   }
   return vertices;
 } /* facet3vertex */
 
 /*---------------------------------
 
   qh_findbestfacet( point, bestoutside, bestdist, isoutside )
     find facet that is furthest below a point
 
     for Delaunay triangulations,
       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
 
   returns:
     if bestoutside is set (e.g., qh_ALL)
       returns best facet that is not upperdelaunay
       if Delaunay and inside, point is outside circumsphere of bestfacet
     else
       returns first facet below point
       if point is inside, returns nearest, !upperdelaunay facet
     distance to facet
     isoutside set if outside of facet
 
   notes:
     For tricoplanar facets, this finds one of the tricoplanar facets closest
     to the point.  For Delaunay triangulations, the point may be inside a
     different tricoplanar facet. See locate a facet with qh_findbestfacet()
 
     If inside, qh_findbestfacet performs an exhaustive search
        this may be too conservative.  Sometimes it is clearly required.
 
     qh_findbestfacet is not used by qhull.
     uses qh.visit_id and qh.coplanarset
 
   see:
     qh_findbest
 */
 facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
            realT *bestdist, boolT *isoutside) {
   facetT *bestfacet= NULL;
   int numpart, totpart= 0;
 
   bestfacet= qh_findbest(point, qh facet_list,
                             bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
                             bestdist, isoutside, &totpart);
   if (*bestdist < -qh DISTround) {
     bestfacet= qh_findfacet_all(point, bestdist, isoutside, &numpart);
     totpart += numpart;
     if ((isoutside && bestoutside)
     || (!isoutside && bestfacet->upperdelaunay)) {
       bestfacet= qh_findbest(point, bestfacet,
                             bestoutside, False, bestoutside,
                             bestdist, isoutside, &totpart);
       totpart += numpart;
     }
   }
   trace3((qh ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
           bestfacet->id, *bestdist, *isoutside, totpart));
   return bestfacet;
 } /* findbestfacet */
 
 /*---------------------------------
 
   qh_findbestlower( facet, point, bestdist, numpart )
     returns best non-upper, non-flipped neighbor of facet for point
     if needed, searches vertex neighbors
 
   returns:
     returns bestdist and updates numpart
 
   notes:
     if Delaunay and inside, point is outside of circumsphere of bestfacet
     called by qh_findbest() for points above an upperdelaunay facet
 
 */
 facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {
   facetT *neighbor, **neighborp, *bestfacet= NULL;
   realT bestdist= -REALmax/2 /* avoid underflow */;
   realT dist;
   vertexT *vertex;
 
   zinc_(Zbestlower);
   FOREACHneighbor_(upperfacet) {
     if (neighbor->upperdelaunay || neighbor->flipped)
       continue;
     (*numpart)++;
     qh_distplane(point, neighbor, &dist);
     if (dist > bestdist) {
       bestfacet= neighbor;
       bestdist= dist;
     }
   }
   if (!bestfacet) {
     zinc_(Zbestlowerv);
     /* rarely called, numpart does not count nearvertex computations */
     vertex= qh_nearvertex(upperfacet, point, &dist);
     qh_vertexneighbors();
     FOREACHneighbor_(vertex) {
       if (neighbor->upperdelaunay || neighbor->flipped)
         continue;
       (*numpart)++;
       qh_distplane(point, neighbor, &dist);
       if (dist > bestdist) {
         bestfacet= neighbor;
         bestdist= dist;
       }
     }
   }
   if (!bestfacet) {
     qh_fprintf(qh ferr, 6228, "\n\
 Qhull internal error (qh_findbestlower): all neighbors of facet %d are flipped or upper Delaunay.\n\
 Please report this error to qhull_bug@qhull.org with the input and all of the output.\n",
        upperfacet->id);
     qh_errexit(qh_ERRqhull, upperfacet, NULL);
   }
   *bestdistp= bestdist;
   trace3((qh ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",
           bestfacet->id, bestdist, upperfacet->id, qh_pointid(point)));
   return bestfacet;
 } /* findbestlower */
 
 /*---------------------------------
 
   qh_findfacet_all( point, bestdist, isoutside, numpart )
     exhaustive search for facet below a point
 
     for Delaunay triangulations,
       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
 
   returns:
     returns first facet below point
     if point is inside,
       returns nearest facet
     distance to facet
     isoutside if point is outside of the hull
     number of distance tests
 
   notes:
     for library users, not used by Qhull
 */
 facetT *qh_findfacet_all(pointT *point, realT *bestdist, boolT *isoutside,
                           int *numpart) {
   facetT *bestfacet= NULL, *facet;
   realT dist;
   int totpart= 0;
 
   *bestdist= -REALmax;
   *isoutside= False;
   FORALLfacets {
     if (facet->flipped || !facet->normal)
       continue;
     totpart++;
     qh_distplane(point, facet, &dist);
     if (dist > *bestdist) {
       *bestdist= dist;
       bestfacet= facet;
       if (dist > qh MINoutside) {
         *isoutside= True;
         break;
       }
     }
   }
   *numpart= totpart;
   trace3((qh ferr, 3016, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",
           getid_(bestfacet), *bestdist, *isoutside, totpart));
   return bestfacet;
 } /* findfacet_all */
 
 /*---------------------------------
 
   qh_findgood( facetlist, goodhorizon )
     identify good facets for qh.PRINTgood
     if qh.GOODvertex>0
       facet includes point as vertex
       if !match, returns goodhorizon
       inactive if qh.MERGING
     if qh.GOODpoint
       facet is visible or coplanar (>0) or not visible (<0)
     if qh.GOODthreshold
       facet->normal matches threshold
     if !goodhorizon and !match,
       selects facet with closest angle
       sets GOODclosest
 
   returns:
     number of new, good facets found
     determines facet->good
     may update qh.GOODclosest
 
   notes:
     qh_findgood_all further reduces the good region
 
   design:
     count good facets
     mark good facets for qh.GOODpoint
     mark good facets for qh.GOODthreshold
     if necessary
       update qh.GOODclosest
 */
 int qh_findgood(facetT *facetlist, int goodhorizon) {
   facetT *facet, *bestfacet= NULL;
   realT angle, bestangle= REALmax, dist;
   int  numgood=0;
 
   FORALLfacet_(facetlist) {
     if (facet->good)
       numgood++;
   }
   if (qh GOODvertex>0 && !qh MERGING) {
     FORALLfacet_(facetlist) {
       if (!qh_isvertex(qh GOODvertexp, facet->vertices)) {
         facet->good= False;
         numgood--;
       }
     }
   }
   if (qh GOODpoint && numgood) {
     FORALLfacet_(facetlist) {
       if (facet->good && facet->normal) {
         zinc_(Zdistgood);
         qh_distplane(qh GOODpointp, facet, &dist);
         if ((qh GOODpoint > 0) ^ (dist > 0.0)) {
           facet->good= False;
           numgood--;
         }
       }
     }
   }
   if (qh GOODthreshold && (numgood || goodhorizon || qh GOODclosest)) {
     FORALLfacet_(facetlist) {
       if (facet->good && facet->normal) {
         if (!qh_inthresholds(facet->normal, &angle)) {
           facet->good= False;
           numgood--;
           if (angle < bestangle) {
             bestangle= angle;
             bestfacet= facet;
           }
         }
       }
     }
     if (!numgood && (!goodhorizon || qh GOODclosest)) {
       if (qh GOODclosest) {
         if (qh GOODclosest->visible)
           qh GOODclosest= NULL;
         else {
           qh_inthresholds(qh GOODclosest->normal, &angle);
           if (angle < bestangle)
             bestfacet= qh GOODclosest;
         }
       }
       if (bestfacet && bestfacet != qh GOODclosest) {
         if (qh GOODclosest)
           qh GOODclosest->good= False;
         qh GOODclosest= bestfacet;
         bestfacet->good= True;
         numgood++;
         trace2((qh ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",
            bestfacet->id, bestangle));
         return numgood;
       }
     }else if (qh GOODclosest) { /* numgood > 0 */
       qh GOODclosest->good= False;
       qh GOODclosest= NULL;
     }
   }
   zadd_(Zgoodfacet, numgood);
   trace2((qh ferr, 2045, "qh_findgood: found %d good facets with %d good horizon\n",
                numgood, goodhorizon));
   if (!numgood && qh GOODvertex>0 && !qh MERGING)
     return goodhorizon;
   return numgood;
 } /* findgood */
 
 /*---------------------------------
 
   qh_findgood_all( facetlist )
     apply other constraints for good facets (used by qh.PRINTgood)
     if qh.GOODvertex
       facet includes (>0) or doesn't include (<0) point as vertex
       if last good facet and ONLYgood, prints warning and continues
     if qh.SPLITthresholds
       facet->normal matches threshold, or if none, the closest one
     calls qh_findgood
     nop if good not used
 
   returns:
     clears facet->good if not good
     sets qh.num_good
 
   notes:
     this is like qh_findgood but more restrictive
 
   design:
     uses qh_findgood to mark good facets
     marks facets for qh.GOODvertex
     marks facets for qh.SPLITthreholds
 */
 void qh_findgood_all(facetT *facetlist) {
   facetT *facet, *bestfacet=NULL;
   realT angle, bestangle= REALmax;
   int  numgood=0, startgood;
 
   if (!qh GOODvertex && !qh GOODthreshold && !qh GOODpoint
   && !qh SPLITthresholds)
     return;
   if (!qh ONLYgood)
     qh_findgood(qh facet_list, 0);
   FORALLfacet_(facetlist) {
     if (facet->good)
       numgood++;
   }
   if (qh GOODvertex <0 || (qh GOODvertex > 0 && qh MERGING)) {
     FORALLfacet_(facetlist) {
       if (facet->good && ((qh GOODvertex > 0) ^ !!qh_isvertex(qh GOODvertexp, facet->vertices))) {
         if (!--numgood) {
           if (qh ONLYgood) {
             qh_fprintf(qh ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
                qh_pointid(qh GOODvertexp), facet->id);
             return;
           }else if (qh GOODvertex > 0)
             qh_fprintf(qh ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",
                 qh GOODvertex-1, qh GOODvertex-1);
           else
             qh_fprintf(qh ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",
                 -qh GOODvertex - 1, -qh GOODvertex - 1);
         }
         facet->good= False;
       }
     }
   }
   startgood= numgood;
   if (qh SPLITthresholds) {
     FORALLfacet_(facetlist) {
       if (facet->good) {
         if (!qh_inthresholds(facet->normal, &angle)) {
           facet->good= False;
           numgood--;
           if (angle < bestangle) {
             bestangle= angle;
             bestfacet= facet;
           }
         }
       }
     }
     if (!numgood && bestfacet) {
       bestfacet->good= True;
       numgood++;
       trace0((qh ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to thresholds\n",
            bestfacet->id, bestangle));
       return;
     }
   }
   qh num_good= numgood;
   trace0((qh ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",
         numgood, startgood));
 } /* findgood_all */
 
 /*---------------------------------
 
   qh_furthestnext()
     set qh.facet_next to facet with furthest of all furthest points
     searches all facets on qh.facet_list
 
   notes:
     this may help avoid precision problems
 */
 void qh_furthestnext(void /* qh.facet_list */) {
   facetT *facet, *bestfacet= NULL;
   realT dist, bestdist= -REALmax;
 
   FORALLfacets {
     if (facet->outsideset) {
 #if qh_COMPUTEfurthest
       pointT *furthest;
       furthest= (pointT*)qh_setlast(facet->outsideset);
       zinc_(Zcomputefurthest);
       qh_distplane(furthest, facet, &dist);
 #else
       dist= facet->furthestdist;
 #endif
       if (dist > bestdist) {
         bestfacet= facet;
         bestdist= dist;
       }
     }
   }
   if (bestfacet) {
     qh_removefacet(bestfacet);
     qh_prependfacet(bestfacet, &qh facet_next);
     trace1((qh ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",
             bestfacet->id, bestdist));
   }
 } /* furthestnext */
 
 /*---------------------------------
 
   qh_furthestout( facet )
     make furthest outside point the last point of outsideset
 
   returns:
     updates facet->outsideset
     clears facet->notfurthest
     sets facet->furthestdist
 
   design:
     determine best point of outsideset
     make it the last point of outsideset
 */
 void qh_furthestout(facetT *facet) {
   pointT *point, **pointp, *bestpoint= NULL;
   realT dist, bestdist= -REALmax;
 
   FOREACHpoint_(facet->outsideset) {
     qh_distplane(point, facet, &dist);
     zinc_(Zcomputefurthest);
     if (dist > bestdist) {
       bestpoint= point;
       bestdist= dist;
     }
   }
   if (bestpoint) {
     qh_setdel(facet->outsideset, point);
     qh_setappend(&facet->outsideset, point);
 #if !qh_COMPUTEfurthest
     facet->furthestdist= bestdist;
 #endif
   }
   facet->notfurthest= False;
   trace3((qh ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",
           qh_pointid(point), facet->id));
 } /* furthestout */
 
 
 /*---------------------------------
 
   qh_infiniteloop( facet )
     report infinite loop error due to facet
 */
 void qh_infiniteloop(facetT *facet) {
 
   qh_fprintf(qh ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");
   qh_errexit(qh_ERRqhull, facet, NULL);
 } /* qh_infiniteloop */
 
 /*---------------------------------
 
   qh_initbuild()
     initialize hull and outside sets with point array
     qh.FIRSTpoint/qh.NUMpoints is point array
     if qh.GOODpoint
       adds qh.GOODpoint to initial hull
 
   returns:
     qh_facetlist with initial hull
     points partioned into outside sets, coplanar sets, or inside
     initializes qh.GOODpointp, qh.GOODvertexp,
 
   design:
     initialize global variables used during qh_buildhull
     determine precision constants and points with max/min coordinate values
       if qh.SCALElast, scale last coordinate(for 'd')
     build initial simplex
     partition input points into facets of initial simplex
     set up lists
     if qh.ONLYgood
       check consistency
       add qh.GOODvertex if defined
 */
 void qh_initbuild( void) {
   setT *maxpoints, *vertices;
   facetT *facet;
   int i, numpart;
   realT dist;
   boolT isoutside;
 
   qh furthest_id= -1;
   qh lastreport= 0;
   qh facet_id= qh vertex_id= qh ridge_id= 0;
   qh visit_id= qh vertex_visit= 0;
   qh maxoutdone= False;
 
   if (qh GOODpoint > 0)
     qh GOODpointp= qh_point(qh GOODpoint-1);
   else if (qh GOODpoint < 0)
     qh GOODpointp= qh_point(-qh GOODpoint-1);
   if (qh GOODvertex > 0)
     qh GOODvertexp= qh_point(qh GOODvertex-1);
   else if (qh GOODvertex < 0)
     qh GOODvertexp= qh_point(-qh GOODvertex-1);
   if ((qh GOODpoint
        && (qh GOODpointp < qh first_point  /* also catches !GOODpointp */
            || qh GOODpointp > qh_point(qh num_points-1)))
     || (qh GOODvertex
         && (qh GOODvertexp < qh first_point  /* also catches !GOODvertexp */
             || qh GOODvertexp > qh_point(qh num_points-1)))) {
     qh_fprintf(qh ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",
              qh num_points-1);
     qh_errexit(qh_ERRinput, NULL, NULL);
   }
   maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim);
   if (qh SCALElast)
     qh_scalelast(qh first_point, qh num_points, qh hull_dim,
                qh MINlastcoord, qh MAXlastcoord, qh MAXwidth);
   qh_detroundoff();
   if (qh DELAUNAY && qh upper_threshold[qh hull_dim-1] > REALmax/2
                   && qh lower_threshold[qh hull_dim-1] < -REALmax/2) {
     for (i=qh_PRINTEND; i--; ) {
       if (qh PRINTout[i] == qh_PRINTgeom && qh DROPdim < 0
           && !qh GOODthreshold && !qh SPLITthresholds)
         break;  /* in this case, don't set upper_threshold */
     }
     if (i < 0) {
       if (qh UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
         qh lower_threshold[qh hull_dim-1]= qh ANGLEround * qh_ZEROdelaunay;
         qh GOODthreshold= True;
       }else {
         qh upper_threshold[qh hull_dim-1]= -qh ANGLEround * qh_ZEROdelaunay;
         if (!qh GOODthreshold)
           qh SPLITthresholds= True; /* build upper-convex hull even if Qg */
           /* qh_initqhull_globals errors if Qg without Pdk/etc. */
       }
     }
   }
   vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points);
   qh_initialhull(vertices);  /* initial qh facet_list */
   qh_partitionall(vertices, qh first_point, qh num_points);
   if (qh PRINToptions1st || qh TRACElevel || qh IStracing) {
     if (qh TRACElevel || qh IStracing)
       qh_fprintf(qh ferr, 8103, "\nTrace level %d for %s | %s\n",
          qh IStracing ? qh IStracing : qh TRACElevel, qh rbox_command, qh qhull_command);
     qh_fprintf(qh ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
   }
   qh_resetlists(False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
   qh facet_next= qh facet_list;
   qh_furthestnext(/* qh.facet_list */);
   if (qh PREmerge) {
     qh cos_max= qh premerge_cos;
     qh centrum_radius= qh premerge_centrum;
   }
   if (qh ONLYgood) {
     if (qh GOODvertex > 0 && qh MERGING) {
       qh_fprintf(qh ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     if (!(qh GOODthreshold || qh GOODpoint
          || (!qh MERGEexact && !qh PREmerge && qh GOODvertexp))) {
       qh_fprintf(qh ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a\n\
 good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     if (qh GOODvertex > 0  && !qh MERGING  /* matches qh_partitionall */
         && !qh_isvertex(qh GOODvertexp, vertices)) {
       facet= qh_findbestnew(qh GOODvertexp, qh facet_list,
                           &dist, !qh_ALL, &isoutside, &numpart);
       zadd_(Zdistgood, numpart);
       if (!isoutside) {
         qh_fprintf(qh ferr, 6153, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
                qh_pointid(qh GOODvertexp));
         qh_errexit(qh_ERRinput, NULL, NULL);
       }
       if (!qh_addpoint(qh GOODvertexp, facet, False)) {
         qh_settempfree(&vertices);
         qh_settempfree(&maxpoints);
         return;
       }
     }
     qh_findgood(qh facet_list, 0);
   }
   qh_settempfree(&vertices);
   qh_settempfree(&maxpoints);
   trace1((qh ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));
 } /* initbuild */
 
 /*---------------------------------
 
   qh_initialhull( vertices )
     constructs the initial hull as a DIM3 simplex of vertices
 
   design:
     creates a simplex (initializes lists)
     determines orientation of simplex
     sets hyperplanes for facets
     doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
     checks for flipped facets and qh.NARROWhull
     checks the result
 */
 void qh_initialhull(setT *vertices) {
   facetT *facet, *firstfacet, *neighbor, **neighborp;
   realT dist, angle, minangle= REALmax;
 #ifndef qh_NOtrace
   int k;
 #endif
 
   qh_createsimplex(vertices);  /* qh.facet_list */
   qh_resetlists(False, qh_RESETvisible);
   qh facet_next= qh facet_list;      /* advance facet when processed */
   qh interior_point= qh_getcenter(vertices);
   firstfacet= qh facet_list;
   qh_setfacetplane(firstfacet);
   zinc_(Znumvisibility); /* needs to be in printsummary */
   qh_distplane(qh interior_point, firstfacet, &dist);
   if (dist > 0) {
     FORALLfacets
       facet->toporient ^= (unsigned char)True;
   }
   FORALLfacets
     qh_setfacetplane(facet);
   FORALLfacets {
     if (!qh_checkflipped(facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
       trace1((qh ferr, 1031, "qh_initialhull: initial orientation incorrect.  Correct all facets\n"));
       facet->flipped= False;
       FORALLfacets {
         facet->toporient ^= (unsigned char)True;
         qh_orientoutside(facet);
       }
       break;
     }
   }
   FORALLfacets {
     if (!qh_checkflipped(facet, NULL, !qh_ALL)) {  /* can happen with 'R0.1' */
       if (qh DELAUNAY && ! qh ATinfinity) {
         if (qh UPPERdelaunay)
           qh_fprintf(qh ferr, 6240, "Qhull input error: Can not compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");
         else
           qh_fprintf(qh ferr, 6239, "Qhull input error: Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points.  Option 'Qz' adds a point \"at infinity\" (above the corresponding paraboloid).\n");
         qh_errexit(qh_ERRinput, NULL, NULL);
       }
       qh_precision("initial facet is coplanar with interior point");
       qh_fprintf(qh ferr, 6154, "qhull precision error: initial facet %d is coplanar with the interior point\n",
                    facet->id);
       qh_errexit(qh_ERRsingular, facet, NULL);
     }
     FOREACHneighbor_(facet) {
       angle= qh_getangle(facet->normal, neighbor->normal);
       minimize_( minangle, angle);
     }
   }
   if (minangle < qh_MAXnarrow && !qh NOnarrow) {
     realT diff= 1.0 + minangle;
 
     qh NARROWhull= True;
     qh_option("_narrow-hull", NULL, &diff);
     if (minangle < qh_WARNnarrow && !qh RERUN && qh PRINTprecision)
       qh_printhelp_narrowhull(qh ferr, minangle);
   }
   zzval_(Zprocessed)= qh hull_dim+1;
   qh_checkpolygon(qh facet_list);
   qh_checkconvex(qh facet_list,   qh_DATAfault);
 #ifndef qh_NOtrace
   if (qh IStracing >= 1) {
     qh_fprintf(qh ferr, 8105, "qh_initialhull: simplex constructed, interior point:");
     for (k=0; k < qh hull_dim; k++)
       qh_fprintf(qh ferr, 8106, " %6.4g", qh interior_point[k]);
     qh_fprintf(qh ferr, 8107, "\n");
   }
 #endif
 } /* initialhull */
 
 /*---------------------------------
 
   qh_initialvertices( dim, maxpoints, points, numpoints )
     determines a non-singular set of initial vertices
     maxpoints may include duplicate points
 
   returns:
     temporary set of dim+1 vertices in descending order by vertex id
     if qh.RANDOMoutside && !qh.ALLpoints
       picks random points
     if dim >= qh_INITIALmax,
       uses min/max x and max points with non-zero determinants
 
   notes:
     unless qh.ALLpoints,
       uses maxpoints as long as determinate is non-zero
 */
 setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) {
   pointT *point, **pointp;
   setT *vertices, *simplex, *tested;
   realT randr;
   int idx, point_i, point_n, k;
   boolT nearzero= False;
 
   vertices= qh_settemp(dim + 1);
   simplex= qh_settemp(dim+1);
   if (qh ALLpoints)
     qh_maxsimplex(dim, NULL, points, numpoints, &simplex);
   else if (qh RANDOMoutside) {
     while (qh_setsize(simplex) != dim+1) {
       randr= qh_RANDOMint;
       randr= randr/(qh_RANDOMmax+1);
       idx= (int)floor(qh num_points * randr);
       while (qh_setin(simplex, qh_point(idx))) {
             idx++; /* in case qh_RANDOMint always returns the same value */
         idx= idx < qh num_points ? idx : 0;
       }
       qh_setappend(&simplex, qh_point(idx));
     }
   }else if (qh hull_dim >= qh_INITIALmax) {
     tested= qh_settemp(dim+1);
     qh_setappend(&simplex, SETfirst_(maxpoints));   /* max and min X coord */
     qh_setappend(&simplex, SETsecond_(maxpoints));
     qh_maxsimplex(fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
     k= qh_setsize(simplex);
     FOREACHpoint_i_(maxpoints) {
       if (point_i & 0x1) {     /* first pick up max. coord. points */
         if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
           qh_detsimplex(point, simplex, k, &nearzero);
           if (nearzero)
             qh_setappend(&tested, point);
           else {
             qh_setappend(&simplex, point);
             if (++k == dim)  /* use search for last point */
               break;
           }
         }
       }
     }
     while (k != dim && (point= (pointT*)qh_setdellast(maxpoints))) {
       if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
         qh_detsimplex(point, simplex, k, &nearzero);
         if (nearzero)
           qh_setappend(&tested, point);
         else {
           qh_setappend(&simplex, point);
           k++;
         }
       }
     }
     idx= 0;
     while (k != dim && (point= qh_point(idx++))) {
       if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
         qh_detsimplex(point, simplex, k, &nearzero);
         if (!nearzero){
           qh_setappend(&simplex, point);
           k++;
         }
       }
     }
     qh_settempfree(&tested);
     qh_maxsimplex(dim, maxpoints, points, numpoints, &simplex);
   }else
     qh_maxsimplex(dim, maxpoints, points, numpoints, &simplex);
   FOREACHpoint_(simplex)
     qh_setaddnth(&vertices, 0, qh_newvertex(point)); /* descending order */
   qh_settempfree(&simplex);
   return vertices;
 } /* initialvertices */
 
 
 /*---------------------------------
 
   qh_isvertex(  )
     returns vertex if point is in vertex set, else returns NULL
 
   notes:
     for qh.GOODvertex
 */
 vertexT *qh_isvertex(pointT *point, setT *vertices) {
   vertexT *vertex, **vertexp;
 
   FOREACHvertex_(vertices) {
     if (vertex->point == point)
       return vertex;
   }
   return NULL;
 } /* isvertex */
 
 /*---------------------------------
 
   qh_makenewfacets( point )
     make new facets from point and qh.visible_list
 
   returns:
     qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
     qh.newvertex_list= list of vertices in new facets with ->newlist set
 
     if (qh.ONLYgood)
       newfacets reference horizon facets, but not vice versa
       ridges reference non-simplicial horizon ridges, but not vice versa
       does not change existing facets
     else
       sets qh.NEWfacets
       new facets attached to horizon facets and ridges
       for visible facets,
         visible->r.replace is corresponding new facet
 
   see also:
     qh_makenewplanes() -- make hyperplanes for facets
     qh_attachnewfacets() -- attachnewfacets if not done here(qh ONLYgood)
     qh_matchnewfacets() -- match up neighbors
     qh_updatevertices() -- update vertex neighbors and delvertices
     qh_deletevisible() -- delete visible facets
     qh_checkpolygon() --check the result
     qh_triangulate() -- triangulate a non-simplicial facet
 
   design:
     for each visible facet
       make new facets to its horizon facets
       update its f.replace
       clear its neighbor set
 */
 vertexT *qh_makenewfacets(pointT *point /*visible_list*/) {
   facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
   vertexT *apex;
   int numnew=0;
 
   qh newfacet_list= qh facet_tail;
   qh newvertex_list= qh vertex_tail;
   apex= qh_newvertex(point);
   qh_appendvertex(apex);
   qh visit_id++;
   if (!qh ONLYgood)
     qh NEWfacets= True;
   FORALLvisible_facets {
     FOREACHneighbor_(visible)
       neighbor->seen= False;
     if (visible->ridges) {
       visible->visitid= qh visit_id;
       newfacet2= qh_makenew_nonsimplicial(visible, apex, &numnew);
     }
     if (visible->simplicial)
       newfacet= qh_makenew_simplicial(visible, apex, &numnew);
     if (!qh ONLYgood) {
       if (newfacet2)  /* newfacet is null if all ridges defined */
         newfacet= newfacet2;
       if (newfacet)
         visible->f.replace= newfacet;
       else
         zinc_(Zinsidevisible);
       SETfirst_(visible->neighbors)= NULL;
     }
   }
   trace1((qh ferr, 1032, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",
           numnew, qh_pointid(point)));
   if (qh IStracing >= 4)
     qh_printfacetlist(qh newfacet_list, NULL, qh_ALL);
   return apex;
 } /* makenewfacets */
 
 /*---------------------------------
 
   qh_matchduplicates( atfacet, atskip, hashsize, hashcount )
     match duplicate ridges in qh.hash_table for atfacet/atskip
     duplicates marked with ->dupridge and qh_DUPLICATEridge
 
   returns:
     picks match with worst merge (min distance apart)
     updates hashcount
 
   see also:
     qh_matchneighbor
 
   notes:
 
   design:
     compute hash value for atfacet and atskip
     repeat twice -- once to make best matches, once to match the rest
       for each possible facet in qh.hash_table
         if it is a matching facet and pass 2
           make match
           unless tricoplanar, mark match for merging (qh_MERGEridge)
           [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
         if it is a matching facet and pass 1
           test if this is a better match
       if pass 1,
         make best match (it will not be merged)
 */
 #ifndef qh_NOmerge
 void qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount) {
   boolT same, ismatch;
   int hash, scan;
   facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;
   int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;
   realT maxdist= -REALmax, mindist, dist2, low, high;
 
   hash= qh_gethash(hashsize, atfacet->vertices, qh hull_dim, 1,
                      SETelem_(atfacet->vertices, atskip));
   trace2((qh ferr, 2046, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",
           atfacet->id, atskip, hash, *hashcount));
   for (makematch= 0; makematch < 2; makematch++) {
     qh visit_id++;
     for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
       zinc_(Zhashlookup);
       nextfacet= NULL;
       newfacet->visitid= qh visit_id;
       for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT));
            scan= (++scan >= hashsize ? 0 : scan)) {
         if (!facet->dupridge || facet->visitid == qh visit_id)
           continue;
         zinc_(Zhashtests);
         if (qh_matchvertices(1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
           ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));
           if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
             if (!makematch) {
               qh_fprintf(qh ferr, 6155, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",
                      facet->id, skip, newfacet->id, newskip, hash);
               qh_errexit2(qh_ERRqhull, facet, newfacet);
             }
           }else if (ismatch && makematch) {
             if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
               SETelem_(facet->neighbors, skip)= newfacet;
               if (newfacet->tricoplanar)
                 SETelem_(newfacet->neighbors, newskip)= facet;
               else
                 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
               *hashcount -= 2; /* removed two unmatched facets */
               trace4((qh ferr, 4059, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",
                     facet->id, skip, newfacet->id, newskip));
             }
           }else if (ismatch) {
             mindist= qh_getdistance(facet, newfacet, &low, &high);
             dist2= qh_getdistance(newfacet, facet, &low, &high);
             minimize_(mindist, dist2);
             if (mindist > maxdist) {
               maxdist= mindist;
               maxmatch= facet;
               maxskip= skip;
               maxmatch2= newfacet;
               maxskip2= newskip;
             }
             trace3((qh ferr, 3018, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",
                     facet->id, skip, newfacet->id, newskip, mindist,
                     maxmatch->id, maxmatch2->id));
           }else { /* !ismatch */
             nextfacet= facet;
             nextskip= skip;
           }
         }
         if (makematch && !facet
         && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {
           qh_fprintf(qh ferr, 6156, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",
                      newfacet->id, newskip, hash);
           qh_errexit(qh_ERRqhull, newfacet, NULL);
         }
       }
     } /* end of for each new facet at hash */
     if (!makematch) {
       if (!maxmatch) {
         qh_fprintf(qh ferr, 6157, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",
                      atfacet->id, atskip, hash);
         qh_errexit(qh_ERRqhull, atfacet, NULL);
       }
       SETelem_(maxmatch->neighbors, maxskip)= maxmatch2;
       SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
       *hashcount -= 2; /* removed two unmatched facets */
       zzinc_(Zmultiridge);
       trace0((qh ferr, 25, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",
               maxmatch->id, maxskip, maxmatch2->id, maxskip2));
       qh_precision("ridge with multiple neighbors");
       if (qh IStracing >= 4)
         qh_errprint("DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);
     }
   }
 } /* matchduplicates */
 
 /*---------------------------------
 
   qh_nearcoplanar()
     for all facets, remove near-inside points from facet->coplanarset
     coplanar points defined by innerplane from qh_outerinner()
 
   returns:
     if qh KEEPcoplanar && !qh KEEPinside
       facet->coplanarset only contains coplanar points
     if qh.JOGGLEmax
       drops inner plane by another qh.JOGGLEmax diagonal since a
         vertex could shift out while a coplanar point shifts in
 
   notes:
     used for qh.PREmerge and qh.JOGGLEmax
     must agree with computation of qh.NEARcoplanar in qh_detroundoff()
   design:
     if not keeping coplanar or inside points
       free all coplanar sets
     else if not keeping both coplanar and inside points
       remove !coplanar or !inside points from coplanar sets
 */
 void qh_nearcoplanar(void /* qh.facet_list */) {
   facetT *facet;
   pointT *point, **pointp;
   int numpart;
   realT dist, innerplane;
 
   if (!qh KEEPcoplanar && !qh KEEPinside) {
     FORALLfacets {
       if (facet->coplanarset)
         qh_setfree( &facet->coplanarset);
     }
   }else if (!qh KEEPcoplanar || !qh KEEPinside) {
     qh_outerinner(NULL, NULL, &innerplane);
     if (qh JOGGLEmax < REALmax/2)
       innerplane -= qh JOGGLEmax * sqrt((realT)qh hull_dim);
     numpart= 0;
     FORALLfacets {
       if (facet->coplanarset) {
         FOREACHpoint_(facet->coplanarset) {
           numpart++;
           qh_distplane(point, facet, &dist);
           if (dist < innerplane) {
             if (!qh KEEPinside)
               SETref_(point)= NULL;
           }else if (!qh KEEPcoplanar)
             SETref_(point)= NULL;
         }
         qh_setcompact(facet->coplanarset);
       }
     }
     zzadd_(Zcheckpart, numpart);
   }
 } /* nearcoplanar */
 
 /*---------------------------------
 
   qh_nearvertex( facet, point, bestdist )
     return nearest vertex in facet to point
 
   returns:
     vertex and its distance
 
   notes:
     if qh.DELAUNAY
       distance is measured in the input set
     searches neighboring tricoplanar facets (requires vertexneighbors)
       Slow implementation.  Recomputes vertex set for each point.
     The vertex set could be stored in the qh.keepcentrum facet.
 */
 vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp) {
   realT bestdist= REALmax, dist;
   vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
   coordT *center;
   facetT *neighbor, **neighborp;
   setT *vertices;
   int dim= qh hull_dim;
 
   if (qh DELAUNAY)
     dim--;
   if (facet->tricoplanar) {
     if (!qh VERTEXneighbors || !facet->center) {
       qh_fprintf(qh ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
       qh_errexit(qh_ERRqhull, facet, NULL);
     }
     vertices= qh_settemp(qh TEMPsize);
     apex= SETfirstt_(facet->vertices, vertexT);
     center= facet->center;
     FOREACHneighbor_(apex) {
       if (neighbor->center == center) {
         FOREACHvertex_(neighbor->vertices)
           qh_setappend(&vertices, vertex);
       }
     }
   }else
     vertices= facet->vertices;
   FOREACHvertex_(vertices) {
     dist= qh_pointdist(vertex->point, point, -dim);
     if (dist < bestdist) {
       bestdist= dist;
       bestvertex= vertex;
     }
   }
   if (facet->tricoplanar)
     qh_settempfree(&vertices);
   *bestdistp= sqrt(bestdist);
   trace3((qh ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",
         bestvertex->id, *bestdistp, facet->id, qh_pointid(point)));
   return bestvertex;
 } /* nearvertex */
 
 /*---------------------------------
 
   qh_newhashtable( newsize )
     returns size of qh.hash_table of at least newsize slots
 
   notes:
     assumes qh.hash_table is NULL
     qh_HASHfactor determines the number of extra slots
     size is not divisible by 2, 3, or 5
 */
 int qh_newhashtable(int newsize) {
   int size;
 
   size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
   while (True) {
     if (newsize<0 || size<0) {
         qh_fprintf(qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d).  Did int overflow due to high-D?\n", newsize, size); /* WARN64 */
         qh_errexit(qhmem_ERRmem, NULL, NULL);
     }
     if ((size%3) && (size%5))
       break;
     size += 2;
     /* loop terminates because there is an infinite number of primes */
   }
   qh hash_table= qh_setnew(size);
   qh_setzero(qh hash_table, 0, size);
   return size;
 } /* newhashtable */
 
 /*---------------------------------
 
   qh_newvertex( point )
     returns a new vertex for point
 */
 vertexT *qh_newvertex(pointT *point) {
   vertexT *vertex;
 
   zinc_(Ztotvertices);
   vertex= (vertexT *)qh_memalloc((int)sizeof(vertexT));
   memset((char *) vertex, (size_t)0, sizeof(vertexT));
   if (qh vertex_id == 0xFFFFFF) {
     qh_fprintf(qh ferr, 6159, "qhull error: more than %d vertices.  ID field overflows and two vertices\n\
 may have the same identifier.  Vertices will not be sorted correctly.\n", 0xFFFFFF);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }
   if (qh vertex_id == qh tracevertex_id)
     qh tracevertex= vertex;
   vertex->id= qh vertex_id++;
   vertex->point= point;
   vertex->dim= (unsigned char)(qh hull_dim <= MAX_vdim ? qh hull_dim : 0);
   trace4((qh ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(vertex->point),
           vertex->id));
   return(vertex);
 } /* newvertex */
 
 /*---------------------------------
 
   qh_nextridge3d( atridge, facet, vertex )
     return next ridge and vertex for a 3d facet
     returns NULL on error
     [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qh_qh.
 
   notes:
     in qh_ORIENTclock order
     this is a O(n^2) implementation to trace all ridges
     be sure to stop on any 2nd visit
     same as QhullRidge::nextRidge3d
     does not use qh_qh or qh_errexit [QhullFacet.cpp]
 
   design:
     for each ridge
       exit if it is the ridge after atridge
 */
 ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {
   vertexT *atvertex, *vertex, *othervertex;
   ridgeT *ridge, **ridgep;
 
   if ((atridge->top == facet) ^ qh_ORIENTclock)
     atvertex= SETsecondt_(atridge->vertices, vertexT);
   else
     atvertex= SETfirstt_(atridge->vertices, vertexT);
   FOREACHridge_(facet->ridges) {
     if (ridge == atridge)
       continue;
     if ((ridge->top == facet) ^ qh_ORIENTclock) {
       othervertex= SETsecondt_(ridge->vertices, vertexT);
       vertex= SETfirstt_(ridge->vertices, vertexT);
     }else {
       vertex= SETsecondt_(ridge->vertices, vertexT);
       othervertex= SETfirstt_(ridge->vertices, vertexT);
     }
     if (vertex == atvertex) {
       if (vertexp)
         *vertexp= othervertex;
       return ridge;
     }
   }
   return NULL;
 } /* nextridge3d */
 #else /* qh_NOmerge */
 void qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount) {
 }
 ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {
 
   return NULL;
 }
 #endif /* qh_NOmerge */
 
 /*---------------------------------
 
   qh_outcoplanar()
     move points from all facets' outsidesets to their coplanarsets
 
   notes:
     for post-processing under qh.NARROWhull
 
   design:
     for each facet
       for each outside point for facet
         partition point into coplanar set
 */
 void qh_outcoplanar(void /* facet_list */) {
   pointT *point, **pointp;
   facetT *facet;
   realT dist;
 
   trace1((qh ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh NARROWhull\n"));
   FORALLfacets {
     FOREACHpoint_(facet->outsideset) {
       qh num_outside--;
       if (qh KEEPcoplanar || qh KEEPnearinside) {
         qh_distplane(point, facet, &dist);
         zinc_(Zpartition);
         qh_partitioncoplanar(point, facet, &dist);
       }
     }
     qh_setfree(&facet->outsideset);
   }
 } /* outcoplanar */
 
 /*---------------------------------
 
   qh_point( id )
     return point for a point id, or NULL if unknown
 
   alternative code:
     return((pointT *)((unsigned   long)qh.first_point
            + (unsigned long)((id)*qh.normal_size)));
 */
 pointT *qh_point(int id) {
 
   if (id < 0)
     return NULL;
   if (id < qh num_points)
     return qh first_point + id * qh hull_dim;
   id -= qh num_points;
   if (id < qh_setsize(qh other_points))
     return SETelemt_(qh other_points, id, pointT);
   return NULL;
 } /* point */
 
 /*---------------------------------
 
   qh_point_add( set, point, elem )
     stores elem at set[point.id]
 
   returns:
     access function for qh_pointfacet and qh_pointvertex
 
   notes:
     checks point.id
 */
 void qh_point_add(setT *set, pointT *point, void *elem) {
   int id, size;
 
   SETreturnsize_(set, size);
   if ((id= qh_pointid(point)) < 0)
     qh_fprintf(qh ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",
       point, id);
   else if (id >= size) {
     qh_fprintf(qh ferr, 6160, "qhull internal errror(point_add): point p%d is out of bounds(%d)\n",
              id, size);
     qh_errexit(qh_ERRqhull, NULL, NULL);
   }else
     SETelem_(set, id)= elem;
 } /* point_add */
 
 
 /*---------------------------------
 
   qh_pointfacet()
     return temporary set of facet for each point
     the set is indexed by point id
 
   notes:
     vertices assigned to one of the facets
     coplanarset assigned to the facet
     outside set assigned to the facet
     NULL if no facet for point (inside)
       includes qh.GOODpointp
 
   access:
     FOREACHfacet_i_(facets) { ... }
     SETelem_(facets, i)
 
   design:
     for each facet
       add each vertex
       add each coplanar point
       add each outside point
 */
 setT *qh_pointfacet(void /*qh.facet_list*/) {
   int numpoints= qh num_points + qh_setsize(qh other_points);
   setT *facets;
   facetT *facet;
   vertexT *vertex, **vertexp;
   pointT *point, **pointp;
 
   facets= qh_settemp(numpoints);
   qh_setzero(facets, 0, numpoints);
   qh vertex_visit++;
   FORALLfacets {
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh vertex_visit) {
         vertex->visitid= qh vertex_visit;
         qh_point_add(facets, vertex->point, facet);
       }
     }
     FOREACHpoint_(facet->coplanarset)
       qh_point_add(facets, point, facet);
     FOREACHpoint_(facet->outsideset)
       qh_point_add(facets, point, facet);
   }
   return facets;
 } /* pointfacet */
 
 /*---------------------------------
 
   qh_pointvertex(  )
     return temporary set of vertices indexed by point id
     entry is NULL if no vertex for a point
       this will include qh.GOODpointp
 
   access:
     FOREACHvertex_i_(vertices) { ... }
     SETelem_(vertices, i)
 */
 setT *qh_pointvertex(void /*qh.facet_list*/) {
   int numpoints= qh num_points + qh_setsize(qh other_points);
   setT *vertices;
   vertexT *vertex;
 
   vertices= qh_settemp(numpoints);
   qh_setzero(vertices, 0, numpoints);
   FORALLvertices
     qh_point_add(vertices, vertex->point, vertex);
   return vertices;
 } /* pointvertex */
 
 
 /*---------------------------------
 
   qh_prependfacet( facet, facetlist )
     prepend facet to the start of a facetlist
 
   returns:
     increments qh.numfacets
     updates facetlist, qh.facet_list, facet_next
 
   notes:
     be careful of prepending since it can lose a pointer.
       e.g., can lose _next by deleting and then prepending before _next
 */
 void qh_prependfacet(facetT *facet, facetT **facetlist) {
   facetT *prevfacet, *list;
 
 
   trace4((qh ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",
           facet->id, getid_(*facetlist)));
   if (!*facetlist)
     (*facetlist)= qh facet_tail;
   list= *facetlist;
   prevfacet= list->previous;
   facet->previous= prevfacet;
   if (prevfacet)
     prevfacet->next= facet;
   list->previous= facet;
   facet->next= *facetlist;
   if (qh facet_list == list)  /* this may change *facetlist */
     qh facet_list= facet;
   if (qh facet_next == list)
     qh facet_next= facet;
   *facetlist= facet;
   qh num_facets++;
 } /* prependfacet */
 
 
 /*---------------------------------
 
   qh_printhashtable( fp )
     print hash table to fp
 
   notes:
     not in I/O to avoid bringing io.c in
 
   design:
     for each hash entry
       if defined
         if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
           print entry and neighbors
 */
 void qh_printhashtable(FILE *fp) {
   facetT *facet, *neighbor;
   int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
   vertexT *vertex, **vertexp;
 
   FOREACHfacet_i_(qh hash_table) {
     if (facet) {
       FOREACHneighbor_i_(facet) {
         if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
           break;
       }
       if (neighbor_i == neighbor_n)
         continue;
       qh_fprintf(fp, 9283, "hash %d f%d ", facet_i, facet->id);
       FOREACHvertex_(facet->vertices)
         qh_fprintf(fp, 9284, "v%d ", vertex->id);
       qh_fprintf(fp, 9285, "\n neighbors:");
       FOREACHneighbor_i_(facet) {
         if (neighbor == qh_MERGEridge)
           id= -3;
         else if (neighbor == qh_DUPLICATEridge)
           id= -2;
         else
           id= getid_(neighbor);
         qh_fprintf(fp, 9286, " %d", id);
       }
       qh_fprintf(fp, 9287, "\n");
     }
   }
 } /* printhashtable */
 
 
 /*---------------------------------
 
   qh_printlists( fp )
     print out facet and vertex list for debugging (without 'f/v' tags)
 */
 void qh_printlists(void) {
   facetT *facet;
   vertexT *vertex;
   int count= 0;
 
   qh_fprintf(qh ferr, 8108, "qh_printlists: facets:");
   FORALLfacets {
     if (++count % 100 == 0)
       qh_fprintf(qh ferr, 8109, "\n     ");
     qh_fprintf(qh ferr, 8110, " %d", facet->id);
   }
   qh_fprintf(qh ferr, 8111, "\n  new facets %d visible facets %d next facet for qh_addpoint %d\n  vertices(new %d):",
      getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_next),
      getid_(qh newvertex_list));
   count = 0;
   FORALLvertices {
     if (++count % 100 == 0)
       qh_fprintf(qh ferr, 8112, "\n     ");
     qh_fprintf(qh ferr, 8113, " %d", vertex->id);
   }
   qh_fprintf(qh ferr, 8114, "\n");
 } /* printlists */
 
 /*---------------------------------
 
   qh_resetlists( stats, qh_RESETvisible )
     reset newvertex_list, newfacet_list, visible_list
     if stats,
       maintains statistics
 
   returns:
     visible_list is empty if qh_deletevisible was called
 */
 void qh_resetlists(boolT stats, boolT resetVisible /*qh.newvertex_list newfacet_list visible_list*/) {
   vertexT *vertex;
   facetT *newfacet, *visible;
   int totnew=0, totver=0;
 
   if (stats) {
     FORALLvertex_(qh newvertex_list)
       totver++;
     FORALLnew_facets
       totnew++;
     zadd_(Zvisvertextot, totver);
     zmax_(Zvisvertexmax, totver);
     zadd_(Znewfacettot, totnew);
     zmax_(Znewfacetmax, totnew);
   }
   FORALLvertex_(qh newvertex_list)
     vertex->newlist= False;
   qh newvertex_list= NULL;
   FORALLnew_facets
     newfacet->newfacet= False;
   qh newfacet_list= NULL;
   if (resetVisible) {
     FORALLvisible_facets {
       visible->f.replace= NULL;
       visible->visible= False;
     }
     qh num_visible= 0;
   }
   qh visible_list= NULL; /* may still have visible facets via qh_triangulate */
   qh NEWfacets= False;
 } /* resetlists */
 
 /*---------------------------------
 
   qh_setvoronoi_all()
     compute Voronoi centers for all facets
     includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
 
   returns:
     facet->center is the Voronoi center
 
   notes:
     this is unused/untested code
       please email bradb@shore.net if this works ok for you
 
   use:
     FORALLvertices {...} to locate the vertex for a point.
     FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
 */
 void qh_setvoronoi_all(void) {
   facetT *facet;
 
   qh_clearcenters(qh_ASvoronoi);
   qh_vertexneighbors();
 
   FORALLfacets {
     if (!facet->normal || !facet->upperdelaunay || qh UPPERdelaunay) {
       if (!facet->center)
         facet->center= qh_facetcenter(facet->vertices);
     }
   }
 } /* setvoronoi_all */
 
 #ifndef qh_NOmerge
 
 /*---------------------------------
 
   qh_triangulate()
     triangulate non-simplicial facets on qh.facet_list,
     if qh VORONOI, sets Voronoi centers of non-simplicial facets
     nop if hasTriangulation
 
   returns:
     all facets simplicial
     each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
 
   notes:
     call after qh_check_output since may switch to Voronoi centers
     Output may overwrite ->f.triowner with ->f.area
 */
 void qh_triangulate(void /*qh.facet_list*/) {
   facetT *facet, *nextfacet, *owner;
   int onlygood= qh ONLYgood;
   facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;
   facetT *orig_neighbor= NULL, *otherfacet;
   vertexT *new_vertex_list= NULL;
   mergeT *merge;
   mergeType mergetype;
   int neighbor_i, neighbor_n;
 
   if (qh hasTriangulation)
       return;
   trace1((qh ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));
   if (qh hull_dim == 2)
     return;
   if (qh VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
     qh_clearcenters(qh_ASvoronoi);
     qh_vertexneighbors();
   }
   qh ONLYgood= False; /* for makenew_nonsimplicial */
   qh visit_id++;
   qh NEWfacets= True;
   qh degen_mergeset= qh_settemp(qh TEMPsize);
   qh newvertex_list= qh vertex_tail;
   for (facet= qh facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
     nextfacet= facet->next;
     if (facet->visible || facet->simplicial)
       continue;
     /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */
     if (!new_facet_list)
       new_facet_list= facet;  /* will be moved to end */
     qh_triangulate_facet(facet, &new_vertex_list);
   }
   trace2((qh ferr, 2047, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));
   for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */
     nextfacet= facet->next;
     if (facet->visible)
       continue;
     if (facet->ridges) {
       if (qh_setsize(facet->ridges) > 0) {
         qh_fprintf(qh ferr, 6161, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);
         qh_errexit(qh_ERRqhull, facet, NULL);
       }
       qh_setfree(&facet->ridges);
     }
     if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
       zinc_(Ztrinull);
       qh_triangulate_null(facet);
     }
   }
   trace2((qh ferr, 2048, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh degen_mergeset)));
   qh visible_list= qh facet_tail;
   while ((merge= (mergeT*)qh_setdellast(qh degen_mergeset))) {
     facet1= merge->facet1;
     facet2= merge->facet2;
     mergetype= merge->type;
     qh_memfree(merge, (int)sizeof(mergeT));
     if (mergetype == MRGmirror) {
       zinc_(Ztrimirror);
       qh_triangulate_mirror(facet1, facet2);
     }
   }
   qh_settempfree(&qh degen_mergeset);
   trace2((qh ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));
   qh newvertex_list= new_vertex_list;  /* all vertices of new facets */
   qh visible_list= NULL;
   qh_updatevertices(/*qh.newvertex_list, empty newfacet_list and visible_list*/);
   qh_resetlists(False, !qh_RESETvisible /*qh.newvertex_list, empty newfacet_list and visible_list*/);
 
   trace2((qh ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));
   trace2((qh ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
   FORALLfacet_(new_facet_list) {
     if (facet->tricoplanar && !facet->visible) {
       FOREACHneighbor_i_(facet) {
         if (neighbor_i == 0) {  /* first iteration */
           if (neighbor->tricoplanar)
             orig_neighbor= neighbor->f.triowner;
           else
             orig_neighbor= neighbor;
         }else {
           if (neighbor->tricoplanar)
             otherfacet= neighbor->f.triowner;
           else
             otherfacet= neighbor;
           if (orig_neighbor == otherfacet) {
             zinc_(Ztridegen);
             facet->degenerate= True;
             break;
           }
         }
       }
     }
   }
 
   trace2((qh ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
   owner= NULL;
   visible= NULL;
   for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */
     nextfacet= facet->next;
     if (facet->visible) {
       if (facet->tricoplanar) { /* a null or mirrored facet */
         qh_delfacet(facet);
         qh num_visible--;
       }else {  /* a non-simplicial facet followed by its tricoplanars */
         if (visible && !owner) {
           /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
           trace2((qh ferr, 2053, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",
                        visible->id));
           qh_delfacet(visible);
           qh num_visible--;
         }
         visible= facet;
         owner= NULL;
       }
     }else if (facet->tricoplanar) {
       if (facet->f.triowner != visible) {
         qh_fprintf(qh ferr, 6162, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
         qh_errexit2(qh_ERRqhull, facet, visible);
       }
       if (owner)
         facet->f.triowner= owner;
       else if (!facet->degenerate) {
         owner= facet;
         nextfacet= visible->next; /* rescan tricoplanar facets with owner */
         facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
         facet->coplanarset= visible->coplanarset;
         facet->outsideset= visible->outsideset;
         visible->coplanarset= NULL;
         visible->outsideset= NULL;
         if (!qh TRInormals) { /* center and normal copied to tricoplanar facets */
           visible->center= NULL;
           visible->normal= NULL;
         }
         qh_delfacet(visible);
         qh num_visible--;
       }
     }
   }
   if (visible && !owner) {
     trace2((qh ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
                  visible->id));
     qh_delfacet(visible);
     qh num_visible--;
   }
   qh NEWfacets= False;
   qh ONLYgood= onlygood; /* restore value */
   if (qh CHECKfrequently)
     qh_checkpolygon(qh facet_list);
   qh hasTriangulation= True;
 } /* triangulate */
 
 
 /*---------------------------------
 
   qh_triangulate_facet(facetA)
     triangulate a non-simplicial facet
       if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
   returns:
     qh.newfacet_list == simplicial facets
       facet->tricoplanar set and ->keepcentrum false
       facet->degenerate set if duplicated apex
       facet->f.trivisible set to facetA
       facet->center copied from facetA (created if qh_ASvoronoi)
         qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
       facet->normal,offset,maxoutside copied from facetA
 
   notes:
       qh_makenew_nonsimplicial uses neighbor->seen for the same
 
   see also:
       qh_addpoint() -- add a point
       qh_makenewfacets() -- construct a cone of facets for a new vertex
 
   design:
       if qh_ASvoronoi,
          compute Voronoi center (facet->center)
       select first vertex (highest ID to preserve ID ordering of ->vertices)
       triangulate from vertex to ridges
       copy facet->center, normal, offset
       update vertex neighbors
 */
 void qh_triangulate_facet(facetT *facetA, vertexT **first_vertex) {
   facetT *newfacet;
   facetT *neighbor, **neighborp;
   vertexT *apex;
   int numnew=0;
 
   trace3((qh ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
 
   if (qh IStracing >= 4)
     qh_printfacet(qh ferr, facetA);
   FOREACHneighbor_(facetA) {
     neighbor->seen= False;
     neighbor->coplanar= False;
   }
   if (qh CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
         && fabs_(facetA->normal[qh hull_dim -1]) >= qh ANGLEround * qh_ZEROdelaunay) {
     facetA->center= qh_facetcenter(facetA->vertices);
   }
   qh_willdelete(facetA, NULL);
   qh newfacet_list= qh facet_tail;
   facetA->visitid= qh visit_id;
   apex= SETfirstt_(facetA->vertices, vertexT);
   qh_makenew_nonsimplicial(facetA, apex, &numnew);
   SETfirst_(facetA->neighbors)= NULL;
   FORALLnew_facets {
     newfacet->tricoplanar= True;
     newfacet->f.trivisible= facetA;
     newfacet->degenerate= False;
     newfacet->upperdelaunay= facetA->upperdelaunay;
     newfacet->good= facetA->good;
     if (qh TRInormals) {
       newfacet->keepcentrum= True;
       newfacet->normal= qh_copypoints(facetA->normal, 1, qh hull_dim);
       if (qh CENTERtype == qh_AScentrum)
         newfacet->center= qh_getcentrum(newfacet);
       else
         newfacet->center= qh_copypoints(facetA->center, 1, qh hull_dim);
     }else {
       newfacet->keepcentrum= False;
       newfacet->normal= facetA->normal;
       newfacet->center= facetA->center;
     }
     newfacet->offset= facetA->offset;
 #if qh_MAXoutside
     newfacet->maxoutside= facetA->maxoutside;
 #endif
   }
   qh_matchnewfacets(/*qh.newfacet_list*/);
   zinc_(Ztricoplanar);
   zadd_(Ztricoplanartot, numnew);
   zmax_(Ztricoplanarmax, numnew);
   qh visible_list= NULL;
   if (!(*first_vertex))
     (*first_vertex)= qh newvertex_list;
   qh newvertex_list= NULL;
   qh_updatevertices(/*qh.newfacet_list, empty visible_list and newvertex_list*/);
   qh_resetlists(False, !qh_RESETvisible /*qh.newfacet_list, empty visible_list and newvertex_list*/);
 } /* triangulate_facet */
 
 /*---------------------------------
 
   qh_triangulate_link(oldfacetA, facetA, oldfacetB, facetB)
     relink facetA to facetB via oldfacets
   returns:
     adds mirror facets to qh degen_mergeset (4-d and up only)
   design:
     if they are already neighbors, the opposing neighbors become MRGmirror facets
 */
 void qh_triangulate_link(facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
   int errmirror= False;
 
   trace3((qh ferr, 3021, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n",
          oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));
   if (qh_setin(facetA->neighbors, facetB)) {
     if (!qh_setin(facetB->neighbors, facetA))
       errmirror= True;
     else
       qh_appendmergeset(facetA, facetB, MRGmirror, NULL);
   }else if (qh_setin(facetB->neighbors, facetA))
     errmirror= True;
   if (errmirror) {
     qh_fprintf(qh ferr, 6163, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",
        facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
     qh_errexit2(qh_ERRqhull, facetA, facetB);
   }
   qh_setreplace(facetB->neighbors, oldfacetB, facetA);
   qh_setreplace(facetA->neighbors, oldfacetA, facetB);
 } /* triangulate_link */
 
 /*---------------------------------
 
   qh_triangulate_mirror(facetA, facetB)
     delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror
       a mirrored facet shares the same vertices of a logical ridge
   design:
     since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
     if they are already neighbors, the opposing neighbors become MRGmirror facets
 */
 void qh_triangulate_mirror(facetT *facetA, facetT *facetB) {
   facetT *neighbor, *neighborB;
   int neighbor_i, neighbor_n;
 
   trace3((qh ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n",
          facetA->id, facetB->id));
   FOREACHneighbor_i_(facetA) {
     neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
     if (neighbor == neighborB)
       continue; /* occurs twice */
     qh_triangulate_link(facetA, neighbor, facetB, neighborB);
   }
   qh_willdelete(facetA, NULL);
   qh_willdelete(facetB, NULL);
 } /* triangulate_mirror */
 
 /*---------------------------------
 
   qh_triangulate_null(facetA)
     remove null facetA from qh_triangulate_facet()
       a null facet has vertex #1 (apex) == vertex #2
   returns:
     adds facetA to ->visible for deletion after qh_updatevertices
     qh degen_mergeset contains mirror facets (4-d and up only)
   design:
     since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
     if they are already neighbors, the opposing neighbors become MRGmirror facets
 */
 void qh_triangulate_null(facetT *facetA) {
   facetT *neighbor, *otherfacet;
 
   trace3((qh ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
   neighbor= SETfirstt_(facetA->neighbors, facetT);
   otherfacet= SETsecondt_(facetA->neighbors, facetT);
   qh_triangulate_link(facetA, neighbor, facetA, otherfacet);
   qh_willdelete(facetA, NULL);
 } /* triangulate_null */
 
 #else /* qh_NOmerge */
 void qh_triangulate(void) {
 }
 #endif /* qh_NOmerge */
 
    /*---------------------------------
 
   qh_vertexintersect( vertexsetA, vertexsetB )
     intersects two vertex sets (inverse id ordered)
     vertexsetA is a temporary set at the top of qhmem.tempstack
 
   returns:
     replaces vertexsetA with the intersection
 
   notes:
     could overwrite vertexsetA if currently too slow
 */
 void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB) {
   setT *intersection;
 
   intersection= qh_vertexintersect_new(*vertexsetA, vertexsetB);
   qh_settempfree(vertexsetA);
   *vertexsetA= intersection;
   qh_settemppush(intersection);
 } /* vertexintersect */
 
 /*---------------------------------
 
   qh_vertexintersect_new(  )
     intersects two vertex sets (inverse id ordered)
 
   returns:
     a new set
 */
 setT *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB) {
   setT *intersection= qh_setnew(qh hull_dim - 1);
   vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
   vertexT **vertexB= SETaddr_(vertexsetB, vertexT);
 
   while (*vertexA && *vertexB) {
     if (*vertexA  == *vertexB) {
       qh_setappend(&intersection, *vertexA);
       vertexA++; vertexB++;
     }else {
       if ((*vertexA)->id > (*vertexB)->id)
         vertexA++;
       else
         vertexB++;
     }
   }
   return intersection;
 } /* vertexintersect_new */
 
 /*---------------------------------
 
   qh_vertexneighbors()
     for each vertex in qh.facet_list,
       determine its neighboring facets
 
   returns:
     sets qh.VERTEXneighbors
       nop if qh.VERTEXneighbors already set
       qh_addpoint() will maintain them
 
   notes:
     assumes all vertex->neighbors are NULL
 
   design:
     for each facet
       for each vertex
         append facet to vertex->neighbors
 */
 void qh_vertexneighbors(void /*qh.facet_list*/) {
   facetT *facet;
   vertexT *vertex, **vertexp;
 
   if (qh VERTEXneighbors)
     return;
   trace1((qh ferr, 1035, "qh_vertexneighbors: determing neighboring facets for each vertex\n"));
   qh vertex_visit++;
   FORALLfacets {
     if (facet->visible)
       continue;
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh vertex_visit) {
         vertex->visitid= qh vertex_visit;
         vertex->neighbors= qh_setnew(qh hull_dim);
       }
       qh_setappend(&vertex->neighbors, facet);
     }
   }
   qh VERTEXneighbors= True;
 } /* vertexneighbors */
 
 /*---------------------------------
 
   qh_vertexsubset( vertexsetA, vertexsetB )
     returns True if vertexsetA is a subset of vertexsetB
     assumes vertexsets are sorted
 
   note:
     empty set is a subset of any other set
 */
 boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
   vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
   vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
 
   while (True) {
     if (!*vertexA)
       return True;
     if (!*vertexB)
       return False;
     if ((*vertexA)->id > (*vertexB)->id)
       return False;
     if (*vertexA  == *vertexB)
       vertexA++;
     vertexB++;
   }
   return False; /* avoid warnings */
 } /* vertexsubset */
diff --git a/src/libqhull/qh-geom.htm b/src/libqhull/qh-geom.htm
index 8aeab33..2e7c5e0 100644
--- a/src/libqhull/qh-geom.htm
+++ b/src/libqhull/qh-geom.htm
@@ -1,293 +1,293 @@
 
 
 
 
 geom.c, geom2.c -- geometric and floating point routines
 
 
 
 
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


geom.c, geom2.c, random.c -- geometric and floating point routines

Geometrically, a vertex is a point with d coordinates and a facet is a halfspace. A halfspace is defined by an oriented hyperplane through the facet's vertices. A hyperplane is defined by d normalized coefficients and an offset. A point is above a facet if its distance to the facet is positive.

Qhull uses floating point coordinates for input points, vertices, halfspace equations, centrums, and an interior point.

Qhull may be configured for single precision or double precision floating point arithmetic (see realT ).

Each floating point operation may incur round-off error (see Merge). The maximum error for distance computations is determined at initialization. The roundoff error in halfspace computation is accounted for by computing the distance from vertices to the halfspace.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to geom.c, geom2.c, geom.h, random.c, random.h

»geometric data types and constants

  • coordT coordinates and coefficients are stored as realT
  • pointT a point is an array of DIM3 coordinates

»mathematical macros

  • fabs_ returns the absolute value of a
  • fmax_ returns the maximum value of a and b
  • fmin_ returns the minimum value of a and b
  • maximize_ maximize a value
  • minimize_ minimize a value
  • det2_ compute a 2-d determinate
  • det3_ compute a 3-d determinate
  • dX, dY, dZ compute the difference between two coordinates

»mathematical functions

»computational geometry functions

»point array functions

»geometric facet functions

»geometric roundoff functions

  • qh_detjoggle determine default joggle for points and distance roundoff error
  • qh_detroundoff determine maximum roundoff error and other precision constants
  • qh_distround compute maximum roundoff error due to a distance computation to a normalized hyperplane
  • qh_divzero divide by a number that is nearly zero
  • qh_maxouter return maximum outer plane
  • qh_outerinner return actual outer and inner planes


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-globa.htm b/src/libqhull/qh-globa.htm index d89f59c..51a4611 100644 --- a/src/libqhull/qh-globa.htm +++ b/src/libqhull/qh-globa.htm @@ -1,161 +1,161 @@ global.c -- global variables and their functions

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


global.c -- global variables and their functions

Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. This allows multiple instances of Qhull to execute at the same time. The structure may be statically allocated or dynamically allocated with malloc(). See QHpointer.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to global.c and libqhull.h

»Qhull's global variables

»Global variable and initialization routines


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-io.htm b/src/libqhull/qh-io.htm index 0ea8f48..0342809 100644 --- a/src/libqhull/qh-io.htm +++ b/src/libqhull/qh-io.htm @@ -1,303 +1,303 @@ io.c -- input and output operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


io.c -- input and output operations

Qhull provides a wide range of input and output options. To organize the code, most output formats use the same driver:

     qh_printbegin( fp, format, facetlist, facets, printall );
 
     FORALLfacet_( facetlist )
       qh_printafacet( fp, format, facet, printall );
 
     FOREACHfacet_( facets )
       qh_printafacet( fp, format, facet, printall );
 
     qh_printend( fp, format );
 

Note the 'printall' flag. It selects whether or not qh_skipfacet() is tested.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to io.c and io.h

»io.h constants and types

»User level functions

»Print functions for all output formats

»Text output functions

»Text utility functions

»Geomview output functions

»Geomview utility functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-mem.htm b/src/libqhull/qh-mem.htm index 4bba0af..5aca0e1 100644 --- a/src/libqhull/qh-mem.htm +++ b/src/libqhull/qh-mem.htm @@ -1,141 +1,141 @@ mem.c -- memory operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


mem.c -- memory operations

Qhull uses quick-fit memory allocation. It maintains a set of free lists for a variety of small allocations. A small request returns a block from the best fitting free list. If the free list is empty, Qhull allocates a block from a reserved buffer.

Use 'T5' to trace memory allocations.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to mem.c and mem.h

»mem.h data types and constants

  • ptr_intT for casting a void* to an integer-type
  • qhmemT global memory structure for mem.c
  • qh_NOmem disable memory allocation

»mem.h macros

»User level functions

»Initialization and termination functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-merge.htm b/src/libqhull/qh-merge.htm index 2bc92b4..625c555 100644 --- a/src/libqhull/qh-merge.htm +++ b/src/libqhull/qh-merge.htm @@ -1,364 +1,364 @@ merge.c -- facet merge operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


merge.c -- facet merge operations

Qhull handles precision problems by merged facets or joggled input. Except for redundant vertices, it corrects a problem by merging two facets. When done, all facets are clearly convex. See Imprecision in Qhull for further information.

Users may joggle the input ('QJn') instead of merging facets.

Qhull detects and corrects the following problems:

  • More than two facets meeting at a ridge. When Qhull creates facets, it creates an even number of facets for each ridge. A convex hull always has two facets for each ridge. More than two facets may be created if non-adjacent facets share a vertex. This is called a duplicate ridge. In 2-d, a duplicate ridge would create a loop of facets.
  • A facet contained in another facet. Facet merging may leave all vertices of one facet as a subset of the vertices of another facet. This is called a redundant facet.
  • A facet with fewer than three neighbors. Facet merging may leave a facet with one or two neighbors. This is called a degenerate facet.
  • A facet with flipped orientation. A facet's hyperplane may define a halfspace that does not include the interior point.This is called a flipped facet.
  • A coplanar horizon facet. A newly processed point may be coplanar with an horizon facet. Qhull creates a new facet without a hyperplane. It links new facets for the same horizon facet together. This is called a samecycle. The new facet or samecycle is merged into the horizon facet.
  • Concave facets. A facet's centrum may be above a neighboring facet. If so, the facets meet at a concave angle.
  • Coplanar facets. A facet's centrum may be coplanar with a neighboring facet (i.e., it is neither clearly below nor clearly above the facet's hyperplane). Qhull removes coplanar facets in independent sets sorted by angle.
  • Redundant vertex. A vertex may have fewer than three neighboring facets. If so, it is redundant and may be renamed to an adjacent vertex without changing the topological structure.This is called a redundant vertex.
-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to merge.c and merge.h

»merge.h data types, macros, and global sets

  • mergeT structure to identify a merge of two facets
  • FOREACHmerge_ assign 'merge' to each merge in merges
  • qh global sets qh.facet_mergeset contains non-convex merges while qh.degen_mergeset contains degenerate and redundant facets

»merge.h constants

»top-level merge functions

»functions for identifying merges

»functions for determining the best merge

»functions for merging facets

»functions for merging a cycle of facets

If a point is coplanar with an horizon facet, the corresponding new facets are linked together (a samecycle) for merging.

»functions for renaming a vertex

»functions for identifying vertices for renaming

»functions for check and trace


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-poly.htm b/src/libqhull/qh-poly.htm index 1bb5937..abab924 100644 --- a/src/libqhull/qh-poly.htm +++ b/src/libqhull/qh-poly.htm @@ -1,481 +1,481 @@ poly.c, poly2.c -- polyhedron operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


poly.c, poly2.c -- polyhedron operations

Qhull uses dimension-free terminology. Qhull builds a polyhedron in dimension d. A polyhedron is a simplicial complex of faces with geometric information for the top and bottom-level faces. A (d-1)-face is a facet, a (d-2)-face is a ridge, and a 0-face is a vertex. For example in 3-d, a facet is a polygon and a ridge is an edge. A facet is built from a ridge (the base) and a vertex (the apex). See Qhull's data structures.

Qhull's primary data structure is a polyhedron. A polyhedron is a list of facets. Each facet has a set of neighboring facets and a set of vertices. Each facet has a hyperplane. For example, a tetrahedron has four facets. If its vertices are a, b, c, d, and its facets are 1, 2, 3, 4, the tetrahedron is

  • facet 1
    • vertices: b c d
    • neighbors: 2 3 4
  • facet 2
    • vertices: a c d
    • neighbors: 1 3 4
  • facet 3
    • vertices: a b d
    • neighbors: 1 2 4
  • facet 4
    • vertices: a b c
    • neighbors: 1 2 3

A facet may be simplicial or non-simplicial. In 3-d, a simplicial facet has three vertices and three neighbors. A nonsimplicial facet has more than three vertices and more than three neighbors. A nonsimplicial facet has a set of ridges and a centrum.

A simplicial facet has an orientation. An orientation is either top or bottom. The flag, facet->toporient, defines the orientation of the facet's vertices. For example in 3-d, 'top' is left-handed orientation (i.e., the vertex order follows the direction of the left-hand fingers when the thumb is pointing away from the center). Except for axis-parallel facets in 5-d and higher, topological orientation determines the geometric orientation of the facet's hyperplane.

A nonsimplicial facet is due to merging two or more facets. The facet's ridge set determine a simplicial decomposition of the facet. Each ridge is a 1-face (i.e., it has two vertices and two neighboring facets). The orientation of a ridge is determined by the order of the neighboring facets. The flag, facet->toporient,is ignored.

A nonsimplicial facet has a centrum for testing convexity. A centrum is a point on the facet's hyperplane that is near the center of the facet. Except for large facets, it is the arithmetic average of the facet's vertices.

A nonsimplicial facet is an approximation that is defined by offsets from the facet's hyperplane. When Qhull finishes, the outer plane is above all points while the inner plane is below the facet's vertices. This guarantees that any exact convex hull passes between the inner and outer planes. The outer plane is defined by facet->maxoutside while the inner plane is computed from the facet's vertices.

Qhull 3.1 includes triangulation of non-simplicial facets ('Qt'). These facets, called tricoplanar, share the same normal. centrum, and Voronoi center. One facet (keepcentrum) owns these data structures. While tricoplanar facets are more accurate than the simplicial facets from joggled input, they may have zero area or flipped orientation.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to poly.c, poly2.c, poly.h, and libqhull.h

»Data types and global lists for polyhedrons

»poly.h constants

  • ALGORITHMfault flag to not report errors in qh_checkconvex()
  • DATAfault flag to report errors in qh_checkconvex()
  • DUPLICATEridge special value for facet->neighbor to indicate a duplicate ridge
  • MERGEridge special value for facet->neighbor to indicate a merged ridge

»Global FORALL macros

»FORALL macros

»FOREACH macros

»Indexed FOREACH macros

  • FOREACHfacet_i_ assign 'facet' and 'facet_i' to each facet in facet set
  • FOREACHneighbor_i_ assign 'neighbor' and 'neighbor_i' to each facet in facet->neighbors or vertex->neighbors
  • FOREACHpoint_i_ assign 'point' and 'point_i' to each point in points set
  • FOREACHridge_i_ assign 'ridge' and 'ridge_i' to each ridge in ridges set
  • FOREACHvertex_i_ assign 'vertex' and 'vertex_i' to each vertex in vertices set
  • FOREACHvertexreverse12_ assign 'vertex' to each vertex in vertex set; reverse the order of first two vertices

»Other macros for polyhedrons

  • getid_ return ID for a facet, ridge, or vertex
  • otherfacet_ return neighboring facet for a ridge in a facet

»Facetlist functions

»Facet functions

»Vertex, ridge, and point functions

»Hashtable functions

»Allocation and deallocation functions

»Check functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-qhull.htm b/src/libqhull/qh-qhull.htm index df877f3..4962dca 100644 --- a/src/libqhull/qh-qhull.htm +++ b/src/libqhull/qh-qhull.htm @@ -1,277 +1,277 @@ libqhull.c -- top-level functions and basic data types

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


libqhull.c -- top-level functions and basic data types

Qhull implements the Quickhull algorithm for computing the convex hull. The Quickhull algorithm combines two well-known algorithms: the 2-d quickhull algorithm and the n-d beneath-beyond algorithm. See Description of Qhull.

This section provides an index to the top-level functions and base data types. The top-level header file, libqhull.h, contains prototypes for these functions.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to libqhull.c, libqhull.h, and unix.c

»libqhull.h and unix.c data types and constants

  • flagT Boolean flag as a bit
  • boolT boolean value, either True or False
  • CENTERtype to distinguish facet->center
  • qh_PRINT output formats for printing (qh.PRINTout)
  • qh_ALL argument flag for selecting everything
  • qh_ERR Qhull exit codes for indicating errors
  • qh_FILEstderr Fake stderr to distinguish error output from normal output [C++ only]
  • qh_prompt version and long prompt for Qhull
  • qh_prompt2 synopsis for Qhull
  • qh_prompt3 concise prompt for Qhull
  • qh_version version stamp

»libqhull.h other macros

  • traceN print trace message if qh.IStracing >= N.
  • QHULL_UNUSED declare an unused variable to avoid warnings.

»Quickhull routines in call order

»Top-level routines for initializing and terminating Qhull (in other modules)

»Top-level routines for reading and modifying the input (in other modules)

»Top-level routines for calling Qhull (in other modules)

»Top-level routines for returning results (in other modules)

»Top-level routines for testing and debugging (in other modules)


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-set.htm b/src/libqhull/qh-set.htm index 1fbd366..e07a610 100644 --- a/src/libqhull/qh-set.htm +++ b/src/libqhull/qh-set.htm @@ -1,306 +1,306 @@ qset.c -- set data type and operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


qset.c -- set data type and operations

Qhull's data structures are constructed from sets. The functions and macros in qset.c construct, iterate, and modify these sets. They are the most frequently called functions in Qhull. For this reason, efficiency is the primary concern.

In Qhull, a set is represented by an unordered array of pointers with a maximum size and a NULL terminator (setT). Most sets correspond to mathematical sets (i.e., the pointers are unique). Some sets are sorted to enforce uniqueness. Some sets are ordered. For example, the order of vertices in a ridge determine the ridge's orientation. If you reverse the order of adjacent vertices, the orientation reverses. Some sets are not mathematical sets. They may be indexed as an array and they may include NULL pointers.

The most common operation on a set is to iterate its members. This is done with a 'FOREACH...' macro. Each set has a custom macro. For example, 'FOREACHvertex_' iterates over a set of vertices. Each vertex is assigned to the variable 'vertex' from the pointer 'vertexp'.

Most sets are constructed by appending elements to the set. The last element of a set is either NULL or the index of the terminating NULL for a partially full set. If a set is full, appending an element copies the set to a larger array.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to qset.c and qset.h

»Data types and constants

  • SETelemsize size of a set element in bytes
  • setT a set with a maximum size and a current size
  • qh global sets global sets for temporary sets, etc.

»FOREACH macros

»Access and size macros

»Internal macros

  • SETsizeaddr_ return pointer to end element of a set (indicates current size)

»address macros

  • SETaddr_ return address of a set's elements
  • SETelemaddr_ return address of the n'th element of a set
  • SETref_ l.h.s. for modifying the current element in a FOREACH iteration

»Allocation and deallocation functions

»Access and predicate functions

»Add functions

»Check and print functions

»Copy, compact, and zero functions

»Delete functions

»Temporary set functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-stat.htm b/src/libqhull/qh-stat.htm index 53c6158..90bc791 100644 --- a/src/libqhull/qh-stat.htm +++ b/src/libqhull/qh-stat.htm @@ -1,161 +1,161 @@ stat.c -- statistical operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


stat.c -- statistical operations

Qhull records many statistics. These functions and macros make it inexpensive to add a statistic.

As with Qhull's global variables, the statistics data structure is accessed by a macro, 'qhstat'. If qh_QHpointer is defined, the macro is 'qh_qhstat->', otherwise the macro is 'qh_qhstat.'. Statistics may be turned off in user.h. If so, all but the 'zz' statistics are ignored.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to stat.c and stat.h

»stat.h types

  • intrealT union of integer and real
  • qhstat global data structure for statistics

»stat.h constants

  • qh_KEEPstatistics 0 turns off most statistics
  • Z..., W... integer (Z) and real (W) statistics
  • ZZstat Z.../W... statistics that remain defined if qh_KEEPstatistics=0
  • ztype zdoc, zinc, etc. for definining statistics

»stat.h macros

  • MAYdebugx called frequently for error trapping
  • zadd_/wadd_ add value to an integer or real statistic
  • zdef_ define a statistic
  • zinc_ increment an integer statistic
  • zmax_/wmax_ update integer or real maximum statistic
  • zmin_/wmin_ update integer or real minimum statistic
  • zval_/wval_ set or return value of a statistic

»stat.c functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qh-user.htm b/src/libqhull/qh-user.htm index b917920..1525f2b 100644 --- a/src/libqhull/qh-user.htm +++ b/src/libqhull/qh-user.htm @@ -1,265 +1,265 @@ user.c -- user-definable operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


user.c -- user-definable operations

This section contains functions and constants that the user may want to change.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to user.c, usermem.c, userprintf.c, userprintf_rbox.c and user.h

»Qhull library constants

»user.h data types and configuration macros

»definition constants

  • qh_DEFAULTbox define default box size for rbox, 'Qbb', and 'QbB' (Geomview expects 0.5)
  • qh_INFINITE on output, indicates Voronoi center at infinity
  • qh_ORIENTclock define convention for orienting facets
  • qh_ZEROdelaunay define facets that are ignored in Delaunay triangulations

»joggle constants

»performance related constants

»memory constants

»conditional compilation

»merge constants

»user.c functions

»usermem.c functions

  • qh_exit exit program, same as exit().
  • qh_free free memory, same as free().
  • qh_malloc allocate memory, same as malloc()

»userprintf.c and userprintf_rbox,c functions

  • qh_fprintf print information from Qhull, sames as fprintf().
  • qh_fprintf_rbox print information from Rbox, sames as fprintf().


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhull/qhull_a.h b/src/libqhull/qhull_a.h index c505fc7..ad40cf3 100644 --- a/src/libqhull/qhull_a.h +++ b/src/libqhull/qhull_a.h @@ -1,151 +1,151 @@ /*
  ---------------------------------
 
    qhull_a.h
    all header files for compiling qhull
 
    see qh-qhull.htm
 
    see libqhull.h for user-level definitions
 
    see user.h for user-definable constants
 
    defines internal functions for libqhull.c global.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/qhull_a.h#5 $$Change: 1663 $
-   $DateTime: 2014/01/19 17:59:16 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/qhull_a.h#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
            full parens around (x?y:z)
            use '#include qhull/qhull_a.h' to avoid name clashes
 */
 
 #ifndef qhDEFqhulla
 #define qhDEFqhulla 1
 
 #include "libqhull.h"  /* Defines data types */
 
 #include "stat.h"
 #include "random.h"
 #include "mem.h"
 #include "qset.h"
 #include "geom.h"
 #include "merge.h"
 #include "poly.h"
 #include "io.h"
 
 #include 
 #include 
 #include 
 #include     /* some compilers will not need float.h */
 #include 
 #include 
 #include 
 #include 
 #include 
 /*** uncomment here and qset.c
      if string.h does not define memcpy()
 #include 
 */
 
 #if qh_CLOCKtype == 2  /* defined in user.h from libqhull.h */
 #include 
 #include 
 #include 
 #endif
 
 #ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
 #pragma warning( disable : 4100)  /* unreferenced formal parameter */
 #pragma warning( disable : 4127)  /* conditional expression is constant */
 #pragma warning( disable : 4706)  /* assignment within conditional function */
 #pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
 #endif
 
 /* ======= -macros- =========== */
 
 /*----------------------------------
 
   traceN((qh ferr, 0Nnnn, "format\n", vars));
     calls qh_fprintf if qh.IStracing >= N
 
     Add debugging traps to the end of qh_fprintf
 
   notes:
     removing tracing reduces code size but doesn't change execution speed
 */
 #ifndef qh_NOtrace
 #define trace0(args) {if (qh IStracing) qh_fprintf args;}
 #define trace1(args) {if (qh IStracing >= 1) qh_fprintf args;}
 #define trace2(args) {if (qh IStracing >= 2) qh_fprintf args;}
 #define trace3(args) {if (qh IStracing >= 3) qh_fprintf args;}
 #define trace4(args) {if (qh IStracing >= 4) qh_fprintf args;}
 #define trace5(args) {if (qh IStracing >= 5) qh_fprintf args;}
 #else /* qh_NOtrace */
 #define trace0(args) {}
 #define trace1(args) {}
 #define trace2(args) {}
 #define trace3(args) {}
 #define trace4(args) {}
 #define trace5(args) {}
 #endif /* qh_NOtrace */
 
 /*----------------------------------
 
 */
 
 /* See Qt's qglobal.h */
 #if !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
 #   define QHULL_OS_WIN
 #elif defined(__MWERKS__) && defined(__INTEL__)
 #   define QHULL_OS_WIN
 #endif
 #if defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN)
 template 
 inline void qhullUnused(T &x) { (void)x; }
 #  define QHULL_UNUSED(x) qhullUnused(x);
 #else
 #  define QHULL_UNUSED(x) (void)x;
 #endif
 
 /***** -libqhull.c prototypes (alphabetical after qhull) ********************/
 
 void    qh_qhull(void);
 boolT   qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist);
 void    qh_buildhull(void);
 void    qh_buildtracing(pointT *furthest, facetT *facet);
 void    qh_build_withrestart(void);
 void    qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
 void    qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
 pointT *qh_nextfurthest(facetT **visible);
 void    qh_partitionall(setT *vertices, pointT *points,int npoints);
 void    qh_partitioncoplanar(pointT *point, facetT *facet, realT *dist);
 void    qh_partitionpoint(pointT *point, facetT *facet);
 void    qh_partitionvisible(boolT allpoints, int *numpoints);
 void    qh_precision(const char *reason);
 void    qh_printsummary(FILE *fp);
 
 /***** -global.c internal prototypes (alphabetical) ***********************/
 
 void    qh_appendprint(qh_PRINT format);
 void    qh_freebuild(boolT allmem);
 void    qh_freebuffers(void);
 void    qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);
 
 /***** -stat.c internal prototypes (alphabetical) ***********************/
 
 void    qh_allstatA(void);
 void    qh_allstatB(void);
 void    qh_allstatC(void);
 void    qh_allstatD(void);
 void    qh_allstatE(void);
 void    qh_allstatE2(void);
 void    qh_allstatF(void);
 void    qh_allstatG(void);
 void    qh_allstatH(void);
 void    qh_freebuffers(void);
 void    qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);
 
 #endif /* qhDEFqhulla */
diff --git a/src/libqhull/qset.c b/src/libqhull/qset.c
index fd777ee..b929367 100644
--- a/src/libqhull/qset.c
+++ b/src/libqhull/qset.c
@@ -1,1339 +1,1339 @@
 /*
  ---------------------------------
 
    qset.c
    implements set manipulations needed for quickhull
 
    see qh-set.htm and qset.h
 
    Be careful of strict aliasing (two pointers of different types
    that reference the same location).  The last slot of a set is
    either the actual size of the set plus 1, or the NULL terminator
    of the set (i.e., setelemT).
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/qset.c#8 $$Change: 1651 $
-   $DateTime: 2014/01/17 08:13:57 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/qset.c#9 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qset.h"
 #include "mem.h"
 #include 
 #include 
 /*** uncomment here and qhull_a.h
      if string.h does not define memcpy()
 #include 
 */
 
 #ifndef qhDEFlibqhull
 typedef struct ridgeT ridgeT;
 typedef struct facetT facetT;
 void    qh_errexit(int exitcode, facetT *, ridgeT *);
 void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
 #  ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
 #  pragma warning( disable : 4127)  /* conditional expression is constant */
 #  pragma warning( disable : 4706)  /* assignment within conditional function */
 #  endif
 #endif
 
 /*=============== internal macros ===========================*/
 
 /*============ functions in alphabetical order ===================*/
 
 /*----------------------------------
 
   qh_setaddnth( setp, nth, newelem)
     adds newelem as n'th element of sorted or unsorted *setp
 
   notes:
     *setp and newelem must be defined
     *setp may be a temp set
     nth=0 is first element
     errors if nth is out of bounds
 
   design:
     expand *setp if empty or full
     move tail of *setp up one
     insert newelem
 */
 void qh_setaddnth(setT **setp, int nth, void *newelem) {
   int oldsize, i;
   setelemT *sizep;          /* avoid strict aliasing */
   setelemT *oldp, *newp;
 
   if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
     qh_setlarger(setp);
     sizep= SETsizeaddr_(*setp);
   }
   oldsize= sizep->i - 1;
   if (nth < 0 || nth > oldsize) {
     qh_fprintf(qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qhmem.ferr, "", *setp);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   sizep->i++;
   oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void);   /* NULL */
   newp= oldp+1;
   for (i=oldsize-nth+1; i--; )  /* move at least NULL  */
     (newp--)->p= (oldp--)->p;       /* may overwrite *sizep */
   newp->p= newelem;
 } /* setaddnth */
 
 
 /*----------------------------------
 
   setaddsorted( setp, newelem )
     adds an newelem into sorted *setp
 
   notes:
     *setp and newelem must be defined
     *setp may be a temp set
     nop if newelem already in set
 
   design:
     find newelem's position in *setp
     insert newelem
 */
 void qh_setaddsorted(setT **setp, void *newelem) {
   int newindex=0;
   void *elem, **elemp;
 
   FOREACHelem_(*setp) {          /* could use binary search instead */
     if (elem < newelem)
       newindex++;
     else if (elem == newelem)
       return;
     else
       break;
   }
   qh_setaddnth(setp, newindex, newelem);
 } /* setaddsorted */
 
 
 /*---------------------------------
 
   qh_setappend( setp, newelem)
     append newelem to *setp
 
   notes:
     *setp may be a temp set
     *setp and newelem may be NULL
 
   design:
     expand *setp if empty or full
     append newelem to *setp
 
 */
 void qh_setappend(setT **setp, void *newelem) {
   setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
   setelemT *endp;
   int count;
 
   if (!newelem)
     return;
   if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
     qh_setlarger(setp);
     sizep= SETsizeaddr_(*setp);
   }
   count= (sizep->i)++ - 1;
   endp= (setelemT *)SETelemaddr_(*setp, count, void);
   (endp++)->p= newelem;
   endp->p= NULL;
 } /* setappend */
 
 /*---------------------------------
 
   qh_setappend_set( setp, setA)
     appends setA to *setp
 
   notes:
     *setp can not be a temp set
     *setp and setA may be NULL
 
   design:
     setup for copy
     expand *setp if it is too small
     append all elements of setA to *setp
 */
 void qh_setappend_set(setT **setp, setT *setA) {
   int sizeA, size;
   setT *oldset;
   setelemT *sizep;
 
   if (!setA)
     return;
   SETreturnsize_(setA, sizeA);
   if (!*setp)
     *setp= qh_setnew(sizeA);
   sizep= SETsizeaddr_(*setp);
   if (!(size= sizep->i))
     size= (*setp)->maxsize;
   else
     size--;
   if (size + sizeA > (*setp)->maxsize) {
     oldset= *setp;
     *setp= qh_setcopy(oldset, sizeA);
     qh_setfree(&oldset);
     sizep= SETsizeaddr_(*setp);
   }
   if (sizeA > 0) {
     sizep->i= size+sizeA+1;   /* memcpy may overwrite */
     memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
   }
 } /* setappend_set */
 
 
 /*---------------------------------
 
   qh_setappend2ndlast( setp, newelem )
     makes newelem the next to the last element in *setp
 
   notes:
     *setp must have at least one element
     newelem must be defined
     *setp may be a temp set
 
   design:
     expand *setp if empty or full
     move last element of *setp up one
     insert newelem
 */
 void qh_setappend2ndlast(setT **setp, void *newelem) {
     setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
     setelemT *endp, *lastp;
     int count;
 
     if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
         qh_setlarger(setp);
         sizep= SETsizeaddr_(*setp);
     }
     count= (sizep->i)++ - 1;
     endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
     lastp= endp-1;
     *(endp++)= *lastp;
     endp->p= NULL;    /* may overwrite *sizep */
     lastp->p= newelem;
 } /* setappend2ndlast */
 
 /*---------------------------------
 
   qh_setcheck( set, typename, id )
     check set for validity
     report errors with typename and id
 
   design:
     checks that maxsize, actual size, and NULL terminator agree
 */
 void qh_setcheck(setT *set, const char *tname, unsigned id) {
   int maxsize, size;
   int waserr= 0;
 
   if (!set)
     return;
   SETreturnsize_(set, size);
   maxsize= set->maxsize;
   if (size > maxsize || !maxsize) {
     qh_fprintf(qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
              size, tname, id, maxsize);
     waserr= 1;
   }else if (set->e[size].p) {
     qh_fprintf(qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
              tname, id, size-1, maxsize);
     waserr= 1;
   }
   if (waserr) {
     qh_setprint(qhmem.ferr, "ERRONEOUS", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
 } /* setcheck */
 
 
 /*---------------------------------
 
   qh_setcompact( set )
     remove internal NULLs from an unsorted set
 
   returns:
     updated set
 
   notes:
     set may be NULL
     it would be faster to swap tail of set into holes, like qh_setdel
 
   design:
     setup pointers into set
     skip NULLs while copying elements to start of set
     update the actual size
 */
 void qh_setcompact(setT *set) {
   int size;
   void **destp, **elemp, **endp, **firstp;
 
   if (!set)
     return;
   SETreturnsize_(set, size);
   destp= elemp= firstp= SETaddr_(set, void);
   endp= destp + size;
   while (1) {
     if (!(*destp++ = *elemp++)) {
       destp--;
       if (elemp > endp)
         break;
     }
   }
   qh_settruncate(set, (int)(destp-firstp));   /* WARN64 */
 } /* setcompact */
 
 
 /*---------------------------------
 
   qh_setcopy( set, extra )
     make a copy of a sorted or unsorted set with extra slots
 
   returns:
     new set
 
   design:
     create a newset with extra slots
     copy the elements to the newset
 
 */
 setT *qh_setcopy(setT *set, int extra) {
   setT *newset;
   int size;
 
   if (extra < 0)
     extra= 0;
   SETreturnsize_(set, size);
   newset= qh_setnew(size+extra);
   SETsizeaddr_(newset)->i= size+1;    /* memcpy may overwrite */
   memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
   return(newset);
 } /* setcopy */
 
 
 /*---------------------------------
 
   qh_setdel( set, oldelem )
     delete oldelem from an unsorted set
 
   returns:
     returns oldelem if found
     returns NULL otherwise
 
   notes:
     set may be NULL
     oldelem must not be NULL;
     only deletes one copy of oldelem in set
 
   design:
     locate oldelem
     update actual size if it was full
     move the last element to the oldelem's location
 */
 void *qh_setdel(setT *set, void *oldelem) {
   setelemT *sizep;
   setelemT *elemp;
   setelemT *lastp;
 
   if (!set)
     return NULL;
   elemp= (setelemT *)SETaddr_(set, void);
   while (elemp->p != oldelem && elemp->p)
     elemp++;
   if (elemp->p) {
     sizep= SETsizeaddr_(set);
     if (!(sizep->i)--)         /*  if was a full set */
       sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
     lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
     elemp->p= lastp->p;      /* may overwrite itself */
     lastp->p= NULL;
     return oldelem;
   }
   return NULL;
 } /* setdel */
 
 
 /*---------------------------------
 
   qh_setdellast( set)
     return last element of set or NULL
 
   notes:
     deletes element from set
     set may be NULL
 
   design:
     return NULL if empty
     if full set
       delete last element and set actual size
     else
       delete last element and update actual size
 */
 void *qh_setdellast(setT *set) {
   int setsize;  /* actually, actual_size + 1 */
   int maxsize;
   setelemT *sizep;
   void *returnvalue;
 
   if (!set || !(set->e[0].p))
     return NULL;
   sizep= SETsizeaddr_(set);
   if ((setsize= sizep->i)) {
     returnvalue= set->e[setsize - 2].p;
     set->e[setsize - 2].p= NULL;
     sizep->i--;
   }else {
     maxsize= set->maxsize;
     returnvalue= set->e[maxsize - 1].p;
     set->e[maxsize - 1].p= NULL;
     sizep->i= maxsize;
   }
   return returnvalue;
 } /* setdellast */
 
 
 /*---------------------------------
 
   qh_setdelnth( set, nth )
     deletes nth element from unsorted set
     0 is first element
 
   returns:
     returns the element (needs type conversion)
 
   notes:
     errors if nth invalid
 
   design:
     setup points and check nth
     delete nth element and overwrite with last element
 */
 void *qh_setdelnth(setT *set, int nth) {
   void *elem;
   setelemT *sizep;
   setelemT *elemp, *lastp;
 
   elemp= (setelemT *)SETelemaddr_(set, nth, void);
   sizep= SETsizeaddr_(set);
   if ((sizep->i--)==0)         /*  if was a full set */
     sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
   if (nth < 0 || nth >= sizep->i) {
     qh_fprintf(qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qhmem.ferr, "", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
   elem= elemp->p;
   elemp->p= lastp->p;      /* may overwrite itself */
   lastp->p= NULL;
   return elem;
 } /* setdelnth */
 
 /*---------------------------------
 
   qh_setdelnthsorted( set, nth )
     deletes nth element from sorted set
 
   returns:
     returns the element (use type conversion)
 
   notes:
     errors if nth invalid
 
   see also:
     setnew_delnthsorted
 
   design:
     setup points and check nth
     copy remaining elements down one
     update actual size
 */
 void *qh_setdelnthsorted(setT *set, int nth) {
   void *elem;
   setelemT *sizep;
   setelemT *newp, *oldp;
 
   sizep= SETsizeaddr_(set);
   if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
     qh_fprintf(qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qhmem.ferr, "", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   newp= (setelemT *)SETelemaddr_(set, nth, void);
   elem= newp->p;
   oldp= newp+1;
   while (((newp++)->p= (oldp++)->p))
     ; /* copy remaining elements and NULL */
   if ((sizep->i--)==0)         /*  if was a full set */
     sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
   return elem;
 } /* setdelnthsorted */
 
 
 /*---------------------------------
 
   qh_setdelsorted( set, oldelem )
     deletes oldelem from sorted set
 
   returns:
     returns oldelem if it was deleted
 
   notes:
     set may be NULL
 
   design:
     locate oldelem in set
     copy remaining elements down one
     update actual size
 */
 void *qh_setdelsorted(setT *set, void *oldelem) {
   setelemT *sizep;
   setelemT *newp, *oldp;
 
   if (!set)
     return NULL;
   newp= (setelemT *)SETaddr_(set, void);
   while(newp->p != oldelem && newp->p)
     newp++;
   if (newp->p) {
     oldp= newp+1;
     while (((newp++)->p= (oldp++)->p))
       ; /* copy remaining elements */
     sizep= SETsizeaddr_(set);
     if ((sizep->i--)==0)    /*  if was a full set */
       sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
     return oldelem;
   }
   return NULL;
 } /* setdelsorted */
 
 
 /*---------------------------------
 
   qh_setduplicate( set, elemsize )
     duplicate a set of elemsize elements
 
   notes:
     use setcopy if retaining old elements
 
   design:
     create a new set
     for each elem of the old set
       create a newelem
       append newelem to newset
 */
 setT *qh_setduplicate(setT *set, int elemsize) {
   void          *elem, **elemp, *newElem;
   setT          *newSet;
   int           size;
 
   if (!(size= qh_setsize(set)))
     return NULL;
   newSet= qh_setnew(size);
   FOREACHelem_(set) {
     newElem= qh_memalloc(elemsize);
     memcpy(newElem, elem, (size_t)elemsize);
     qh_setappend(&newSet, newElem);
   }
   return newSet;
 } /* setduplicate */
 
 
 /*---------------------------------
 
   qh_setendpointer( set )
     Returns pointer to NULL terminator of a set's elements
     set can not be NULL
 
 */
 void **qh_setendpointer(setT *set) {
 
   setelemT *sizep= SETsizeaddr_(set);
   int n= sizep->i;
   return (n ? &set->e[n-1].p : &sizep->p);
 } /* qh_setendpointer */
 
 /*---------------------------------
 
   qh_setequal( setA, setB )
     returns 1 if two sorted sets are equal, otherwise returns 0
 
   notes:
     either set may be NULL
 
   design:
     check size of each set
     setup pointers
     compare elements of each set
 */
 int qh_setequal(setT *setA, setT *setB) {
   void **elemAp, **elemBp;
   int sizeA= 0, sizeB= 0;
 
   if (setA) {
     SETreturnsize_(setA, sizeA);
   }
   if (setB) {
     SETreturnsize_(setB, sizeB);
   }
   if (sizeA != sizeB)
     return 0;
   if (!sizeA)
     return 1;
   elemAp= SETaddr_(setA, void);
   elemBp= SETaddr_(setB, void);
   if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
     return 1;
   return 0;
 } /* setequal */
 
 
 /*---------------------------------
 
   qh_setequal_except( setA, skipelemA, setB, skipelemB )
     returns 1 if sorted setA and setB are equal except for skipelemA & B
 
   returns:
     false if either skipelemA or skipelemB are missing
 
   notes:
     neither set may be NULL
 
     if skipelemB is NULL,
       can skip any one element of setB
 
   design:
     setup pointers
     search for skipelemA, skipelemB, and mismatches
     check results
 */
 int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
   void **elemA, **elemB;
   int skip=0;
 
   elemA= SETaddr_(setA, void);
   elemB= SETaddr_(setB, void);
   while (1) {
     if (*elemA == skipelemA) {
       skip++;
       elemA++;
     }
     if (skipelemB) {
       if (*elemB == skipelemB) {
         skip++;
         elemB++;
       }
     }else if (*elemA != *elemB) {
       skip++;
       if (!(skipelemB= *elemB++))
         return 0;
     }
     if (!*elemA)
       break;
     if (*elemA++ != *elemB++)
       return 0;
   }
   if (skip != 2 || *elemB)
     return 0;
   return 1;
 } /* setequal_except */
 
 
 /*---------------------------------
 
   qh_setequal_skip( setA, skipA, setB, skipB )
     returns 1 if sorted setA and setB are equal except for elements skipA & B
 
   returns:
     false if different size
 
   notes:
     neither set may be NULL
 
   design:
     setup pointers
     search for mismatches while skipping skipA and skipB
 */
 int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
   void **elemA, **elemB, **skipAp, **skipBp;
 
   elemA= SETaddr_(setA, void);
   elemB= SETaddr_(setB, void);
   skipAp= SETelemaddr_(setA, skipA, void);
   skipBp= SETelemaddr_(setB, skipB, void);
   while (1) {
     if (elemA == skipAp)
       elemA++;
     if (elemB == skipBp)
       elemB++;
     if (!*elemA)
       break;
     if (*elemA++ != *elemB++)
       return 0;
   }
   if (*elemB)
     return 0;
   return 1;
 } /* setequal_skip */
 
 
 /*---------------------------------
 
   qh_setfree( setp )
     frees the space occupied by a sorted or unsorted set
 
   returns:
     sets setp to NULL
 
   notes:
     set may be NULL
 
   design:
     free array
     free set
 */
 void qh_setfree(setT **setp) {
   int size;
   void **freelistp;  /* used !qh_NOmem */
 
   if (*setp) {
     size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
     if (size <= qhmem.LASTsize) {
       qh_memfree_(*setp, size, freelistp);
     }else
       qh_memfree(*setp, size);
     *setp= NULL;
   }
 } /* setfree */
 
 
 /*---------------------------------
 
   qh_setfree2( setp, elemsize )
     frees the space occupied by a set and its elements
 
   notes:
     set may be NULL
 
   design:
     free each element
     free set
 */
 void qh_setfree2(setT **setp, int elemsize) {
   void          *elem, **elemp;
 
   FOREACHelem_(*setp)
     qh_memfree(elem, elemsize);
   qh_setfree(setp);
 } /* setfree2 */
 
 
 
 /*---------------------------------
 
   qh_setfreelong( setp )
     frees a set only if it's in long memory
 
   returns:
     sets setp to NULL if it is freed
 
   notes:
     set may be NULL
 
   design:
     if set is large
       free it
 */
 void qh_setfreelong(setT **setp) {
   int size;
 
   if (*setp) {
     size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
     if (size > qhmem.LASTsize) {
       qh_memfree(*setp, size);
       *setp= NULL;
     }
   }
 } /* setfreelong */
 
 
 /*---------------------------------
 
   qh_setin( set, setelem )
     returns 1 if setelem is in a set, 0 otherwise
 
   notes:
     set may be NULL or unsorted
 
   design:
     scans set for setelem
 */
 int qh_setin(setT *set, void *setelem) {
   void *elem, **elemp;
 
   FOREACHelem_(set) {
     if (elem == setelem)
       return 1;
   }
   return 0;
 } /* setin */
 
 
 /*---------------------------------
 
   qh_setindex( set, atelem )
     returns the index of atelem in set.
     returns -1, if not in set or maxsize wrong
 
   notes:
     set may be NULL and may contain nulls.
     NOerrors returned (qh_pointid, QhullPoint::id)
 
   design:
     checks maxsize
     scans set for atelem
 */
 int qh_setindex(setT *set, void *atelem) {
   void **elem;
   int size, i;
 
   if (!set)
     return -1;
   SETreturnsize_(set, size);
   if (size > set->maxsize)
     return -1;
   elem= SETaddr_(set, void);
   for (i=0; i < size; i++) {
     if (*elem++ == atelem)
       return i;
   }
   return -1;
 } /* setindex */
 
 
 /*---------------------------------
 
   qh_setlarger( oldsetp )
     returns a larger set that contains all elements of *oldsetp
 
   notes:
     the set is at least twice as large
     if temp set, updates qhmem.tempstack
 
   design:
     creates a new set
     copies the old set to the new set
     updates pointers in tempstack
     deletes the old set
 */
 void qh_setlarger(setT **oldsetp) {
   int size= 1;
   setT *newset, *set, **setp, *oldset;
   setelemT *sizep;
   setelemT *newp, *oldp;
 
   if (*oldsetp) {
     oldset= *oldsetp;
     SETreturnsize_(oldset, size);
     qhmem.cntlarger++;
     qhmem.totlarger += size+1;
     newset= qh_setnew(2 * size);
     oldp= (setelemT *)SETaddr_(oldset, void);
     newp= (setelemT *)SETaddr_(newset, void);
     memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize);
     sizep= SETsizeaddr_(newset);
     sizep->i= size+1;
     FOREACHset_((setT *)qhmem.tempstack) {
       if (set == oldset)
         *(setp-1)= newset;
     }
     qh_setfree(oldsetp);
   }else
     newset= qh_setnew(3);
   *oldsetp= newset;
 } /* setlarger */
 
 
 /*---------------------------------
 
   qh_setlast( set )
     return last element of set or NULL (use type conversion)
 
   notes:
     set may be NULL
 
   design:
     return last element
 */
 void *qh_setlast(setT *set) {
   int size;
 
   if (set) {
     size= SETsizeaddr_(set)->i;
     if (!size)
       return SETelem_(set, set->maxsize - 1);
     else if (size > 1)
       return SETelem_(set, size - 2);
   }
   return NULL;
 } /* setlast */
 
 
 /*---------------------------------
 
   qh_setnew( setsize )
     creates and allocates space for a set
 
   notes:
     setsize means the number of elements (!including the NULL terminator)
     use qh_settemp/qh_setfreetemp if set is temporary
 
   design:
     allocate memory for set
     roundup memory if small set
     initialize as empty set
 */
 setT *qh_setnew(int setsize) {
   setT *set;
   int sizereceived; /* used !qh_NOmem */
   int size;
   void **freelistp; /* used !qh_NOmem */
 
   if (!setsize)
     setsize++;
   size= sizeof(setT) + setsize * SETelemsize;
   if (size>0 && size <= qhmem.LASTsize) {
     qh_memalloc_(size, freelistp, set, setT);
 #ifndef qh_NOmem
     sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
     if (sizereceived > size)
       setsize += (sizereceived - size)/SETelemsize;
 #endif
   }else
     set= (setT*)qh_memalloc(size);
   set->maxsize= setsize;
   set->e[setsize].i= 1;
   set->e[0].p= NULL;
   return(set);
 } /* setnew */
 
 
 /*---------------------------------
 
   qh_setnew_delnthsorted( set, size, nth, prepend )
     creates a sorted set not containing nth element
     if prepend, the first prepend elements are undefined
 
   notes:
     set must be defined
     checks nth
     see also: setdelnthsorted
 
   design:
     create new set
     setup pointers and allocate room for prepend'ed entries
     append head of old set to new set
     append tail of old set to new set
 */
 setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
   setT *newset;
   void **oldp, **newp;
   int tailsize= size - nth -1, newsize;
 
   if (tailsize < 0) {
     qh_fprintf(qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qhmem.ferr, "", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   newsize= size-1 + prepend;
   newset= qh_setnew(newsize);
   newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
   oldp= SETaddr_(set, void);
   newp= SETaddr_(newset, void) + prepend;
   switch (nth) {
   case 0:
     break;
   case 1:
     *(newp++)= *oldp++;
     break;
   case 2:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 3:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 4:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   default:
     memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
     newp += nth;
     oldp += nth;
     break;
   }
   oldp++;
   switch (tailsize) {
   case 0:
     break;
   case 1:
     *(newp++)= *oldp++;
     break;
   case 2:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 3:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 4:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   default:
     memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
     newp += tailsize;
   }
   *newp= NULL;
   return(newset);
 } /* setnew_delnthsorted */
 
 
 /*---------------------------------
 
   qh_setprint( fp, string, set )
     print set elements to fp with identifying string
 
   notes:
     never errors
 */
 void qh_setprint(FILE *fp, const char* string, setT *set) {
   int size, k;
 
   if (!set)
     qh_fprintf(fp, 9346, "%s set is null\n", string);
   else {
     SETreturnsize_(set, size);
     qh_fprintf(fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
              string, set, set->maxsize, size);
     if (size > set->maxsize)
       size= set->maxsize+1;
     for (k=0; k < size; k++)
       qh_fprintf(fp, 9348, " %p", set->e[k].p);
     qh_fprintf(fp, 9349, "\n");
   }
 } /* setprint */
 
 /*---------------------------------
 
   qh_setreplace( set, oldelem, newelem )
     replaces oldelem in set with newelem
 
   notes:
     errors if oldelem not in the set
     newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
 
   design:
     find oldelem
     replace with newelem
 */
 void qh_setreplace(setT *set, void *oldelem, void *newelem) {
   void **elemp;
 
   elemp= SETaddr_(set, void);
   while (*elemp != oldelem && *elemp)
     elemp++;
   if (*elemp)
     *elemp= newelem;
   else {
     qh_fprintf(qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
        oldelem);
     qh_setprint(qhmem.ferr, "", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
 } /* setreplace */
 
 
 /*---------------------------------
 
   qh_setsize( set )
     returns the size of a set
 
   notes:
     errors if set's maxsize is incorrect
     same as SETreturnsize_(set)
     same code for qh_setsize [qset.c] and QhullSetBase::count
 
   design:
     determine actual size of set from maxsize
 */
 int qh_setsize(setT *set) {
   int size;
   setelemT *sizep;
 
   if (!set)
     return(0);
   sizep= SETsizeaddr_(set);
   if ((size= sizep->i)) {
     size--;
     if (size > set->maxsize) {
       qh_fprintf(qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
                size, set->maxsize);
       qh_setprint(qhmem.ferr, "set: ", set);
       qh_errexit(qhmem_ERRqhull, NULL, NULL);
     }
   }else
     size= set->maxsize;
   return size;
 } /* setsize */
 
 /*---------------------------------
 
   qh_settemp( setsize )
     return a stacked, temporary set of upto setsize elements
 
   notes:
     use settempfree or settempfree_all to release from qhmem.tempstack
     see also qh_setnew
 
   design:
     allocate set
     append to qhmem.tempstack
 
 */
 setT *qh_settemp(int setsize) {
   setT *newset;
 
   newset= qh_setnew(setsize);
   qh_setappend(&qhmem.tempstack, newset);
   if (qhmem.IStracing >= 5)
     qh_fprintf(qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
        newset, newset->maxsize, qh_setsize(qhmem.tempstack));
   return newset;
 } /* settemp */
 
 /*---------------------------------
 
   qh_settempfree( set )
     free temporary set at top of qhmem.tempstack
 
   notes:
     nop if set is NULL
     errors if set not from previous   qh_settemp
 
   to locate errors:
     use 'T2' to find source and then find mis-matching qh_settemp
 
   design:
     check top of qhmem.tempstack
     free it
 */
 void qh_settempfree(setT **set) {
   setT *stackedset;
 
   if (!*set)
     return;
   stackedset= qh_settemppop();
   if (stackedset != *set) {
     qh_settemppush(stackedset);
     qh_fprintf(qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
              *set, qh_setsize(*set), qh_setsize(qhmem.tempstack)+1,
              stackedset, qh_setsize(stackedset));
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   qh_setfree(set);
 } /* settempfree */
 
 /*---------------------------------
 
   qh_settempfree_all(  )
     free all temporary sets in qhmem.tempstack
 
   design:
     for each set in tempstack
       free set
     free qhmem.tempstack
 */
 void qh_settempfree_all(void) {
   setT *set, **setp;
 
   FOREACHset_(qhmem.tempstack)
     qh_setfree(&set);
   qh_setfree(&qhmem.tempstack);
 } /* settempfree_all */
 
 /*---------------------------------
 
   qh_settemppop(  )
     pop and return temporary set from qhmem.tempstack
 
   notes:
     the returned set is permanent
 
   design:
     pop and check top of qhmem.tempstack
 */
 setT *qh_settemppop(void) {
   setT *stackedset;
 
   stackedset= (setT*)qh_setdellast(qhmem.tempstack);
   if (!stackedset) {
     qh_fprintf(qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   if (qhmem.IStracing >= 5)
     qh_fprintf(qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
        qh_setsize(qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
   return stackedset;
 } /* settemppop */
 
 /*---------------------------------
 
   qh_settemppush( set )
     push temporary set unto qhmem.tempstack (makes it temporary)
 
   notes:
     duplicates settemp() for tracing
 
   design:
     append set to tempstack
 */
 void qh_settemppush(setT *set) {
     if (!set) {
         fprintf (qhmem.ferr, "qhull error (qh_settemppush): can not push a NULL temp\n");
         qh_errexit(qhmem_ERRqhull, NULL, NULL);
     }
   qh_setappend(&qhmem.tempstack, set);
   if (qhmem.IStracing >= 5)
     qh_fprintf(qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
       qh_setsize(qhmem.tempstack), set, qh_setsize(set));
 } /* settemppush */
 
 
 /*---------------------------------
 
   qh_settruncate( set, size )
     truncate set to size elements
 
   notes:
     set must be defined
 
   see:
     SETtruncate_
 
   design:
     check size
     update actual size of set
 */
 void qh_settruncate(setT *set, int size) {
 
   if (size < 0 || size > set->maxsize) {
     qh_fprintf(qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
     qh_setprint(qhmem.ferr, "", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   set->e[set->maxsize].i= size+1;   /* maybe overwritten */
   set->e[size].p= NULL;
 } /* settruncate */
 
 /*---------------------------------
 
   qh_setunique( set, elem )
     add elem to unsorted set unless it is already in set
 
   notes:
     returns 1 if it is appended
 
   design:
     if elem not in set
       append elem to set
 */
 int qh_setunique(setT **set, void *elem) {
 
   if (!qh_setin(*set, elem)) {
     qh_setappend(set, elem);
     return 1;
   }
   return 0;
 } /* setunique */
 
 /*---------------------------------
 
   qh_setzero( set, index, size )
     zero elements from index on
     set actual size of set to size
 
   notes:
     set must be defined
     the set becomes an indexed set (can not use FOREACH...)
 
   see also:
     qh_settruncate
 
   design:
     check index and size
     update actual size
     zero elements starting at e[index]
 */
 void qh_setzero(setT *set, int idx, int size) {
   int count;
 
   if (idx < 0 || idx >= size || size > set->maxsize) {
     qh_fprintf(qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
     qh_setprint(qhmem.ferr, "", set);
     qh_errexit(qhmem_ERRqhull, NULL, NULL);
   }
   set->e[set->maxsize].i=  size+1;  /* may be overwritten */
   count= size - idx + 1;   /* +1 for NULL terminator */
   memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
 } /* setzero */
 
 
diff --git a/src/libqhull/qset.h b/src/libqhull/qset.h
index 38116ea..679ff11 100644
--- a/src/libqhull/qset.h
+++ b/src/libqhull/qset.h
@@ -1,488 +1,488 @@
 /*
  ---------------------------------
 
    qset.h
      header file for qset.c that implements set
 
    see qh-set.htm and qset.c
 
    only uses mem.c, malloc/free
 
    for error handling, writes message and calls
       qh_errexit(qhmem_ERRqhull, NULL, NULL);
 
    set operations satisfy the following properties:
     - sets have a max size, the actual size (if different) is stored at the end
     - every set is NULL terminated
     - sets may be sorted or unsorted, the caller must distinguish this
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/qset.h#5 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/qset.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFset
 #define qhDEFset 1
 
 #include 
 
 /*================= -structures- ===============*/
 
 #ifndef DEFsetT
 #define DEFsetT 1
 typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
 #endif
 
 /*------------------------------------------
 
 setT
   a set or list of pointers with maximum size and actual size.
 
 variations:
   unsorted, unique   -- a list of unique pointers with NULL terminator
                            user guarantees uniqueness
   sorted             -- a sorted list of unique pointers with NULL terminator
                            qset.c guarantees uniqueness
   unsorted           -- a list of pointers terminated with NULL
   indexed            -- an array of pointers with NULL elements
 
 structure for set of n elements:
 
         --------------
         |  maxsize
         --------------
         |  e[0] - a pointer, may be NULL for indexed sets
         --------------
         |  e[1]
 
         --------------
         |  ...
         --------------
         |  e[n-1]
         --------------
         |  e[n] = NULL
         --------------
         |  ...
         --------------
         |  e[maxsize] - n+1 or NULL (determines actual size of set)
         --------------
 
 */
 
 /*-- setelemT -- internal type to allow both pointers and indices
 */
 typedef union setelemT setelemT;
 union setelemT {
   void    *p;
   int      i;         /* integer used for e[maxSize] */
 };
 
 struct setT {
   int maxsize;          /* maximum number of elements (except NULL) */
   setelemT e[1];        /* array of pointers, tail is NULL */
                         /* last slot (unless NULL) is actual size+1
                            e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
                         /* this may generate a warning since e[] contains
                            maxsize elements */
 };
 
 /*=========== -constants- =========================*/
 
 /*-------------------------------------
 
   SETelemsize
     size of a set element in bytes
 */
 #define SETelemsize ((int)sizeof(setelemT))
 
 
 /*=========== -macros- =========================*/
 
 /*-------------------------------------
 
    FOREACHsetelement_(type, set, variable)
      define FOREACH iterator
 
    declare:
      assumes *variable and **variablep are declared
      no space in "variable)" [DEC Alpha cc compiler]
 
    each iteration:
      variable is set element
      variablep is one beyond variable.
 
    to repeat an element:
      variablep--; / *repeat* /
 
    at exit:
      variable is NULL at end of loop
 
    example:
      #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
 
    notes:
      use FOREACHsetelement_i_() if need index or include NULLs
 
    WARNING:
      nested loops can't use the same variable (define another FOREACH)
 
      needs braces if nested inside another FOREACH
      this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
 */
 #define FOREACHsetelement_(type, set, variable) \
         if (((variable= NULL), set)) for (\
           variable##p= (type **)&((set)->e[0].p); \
           (variable= *variable##p++);)
 
 /*------------------------------------------
 
    FOREACHsetelement_i_(type, set, variable)
      define indexed FOREACH iterator
 
    declare:
      type *variable, variable_n, variable_i;
 
    each iteration:
      variable is set element, may be NULL
      variable_i is index, variable_n is qh_setsize()
 
    to repeat an element:
      variable_i--; variable_n-- repeats for deleted element
 
    at exit:
      variable==NULL and variable_i==variable_n
 
    example:
      #define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet )
 
    WARNING:
      nested loops can't use the same variable (define another FOREACH)
 
      needs braces if nested inside another FOREACH
      this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
 */
 #define FOREACHsetelement_i_(type, set, variable) \
         if (((variable= NULL), set)) for (\
           variable##_i= 0, variable= (type *)((set)->e[0].p), \
                    variable##_n= qh_setsize(set);\
           variable##_i < variable##_n;\
           variable= (type *)((set)->e[++variable##_i].p) )
 
 /*----------------------------------------
 
    FOREACHsetelementreverse_(type, set, variable)-
      define FOREACH iterator in reverse order
 
    declare:
      assumes *variable and **variablep are declared
      also declare 'int variabletemp'
 
    each iteration:
      variable is set element
 
    to repeat an element:
      variabletemp++; / *repeat* /
 
    at exit:
      variable is NULL
 
    example:
      #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
 
    notes:
      use FOREACHsetelementreverse12_() to reverse first two elements
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHsetelementreverse_(type, set, variable) \
         if (((variable= NULL), set)) for (\
            variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
            variable; variable= \
            ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
 
 /*-------------------------------------
 
    FOREACHsetelementreverse12_(type, set, variable)-
      define FOREACH iterator with e[1] and e[0] reversed
 
    declare:
      assumes *variable and **variablep are declared
 
    each iteration:
      variable is set element
      variablep is one after variable.
 
    to repeat an element:
      variablep--; / *repeat* /
 
    at exit:
      variable is NULL at end of loop
 
    example
      #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
 
    notes:
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHsetelementreverse12_(type, set, variable) \
         if (((variable= NULL), set)) for (\
           variable##p= (type **)&((set)->e[1].p); \
           (variable= *variable##p); \
           variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
               (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
 
 /*-------------------------------------
 
    FOREACHelem_( set )-
      iterate elements in a set
 
    declare:
      void *elem, *elemp;
 
    each iteration:
      elem is set element
      elemp is one beyond
 
    to repeat an element:
      elemp--; / *repeat* /
 
    at exit:
      elem == NULL at end of loop
 
    example:
      FOREACHelem_(set) {
 
    notes:
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
 
 /*-------------------------------------
 
    FOREACHset_( set )-
      iterate a set of sets
 
    declare:
      setT *set, **setp;
 
    each iteration:
      set is set element
      setp is one beyond
 
    to repeat an element:
      setp--; / *repeat* /
 
    at exit:
      set == NULL at end of loop
 
    example
      FOREACHset_(sets) {
 
    notes:
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
 
 /*-------------------------------------------
 
    SETindex_( set, elem )
      return index of elem in set
 
    notes:
      for use with FOREACH iteration
      WARN64 -- Maximum set size is 2G
 
    example:
      i= SETindex_(ridges, ridge)
 */
 #define SETindex_(set, elem) ((int)((void **)elem##p - (void **)&(set)->e[1].p))
 
 /*-----------------------------------------
 
    SETref_( elem )
      l.h.s. for modifying the current element in a FOREACH iteration
 
    example:
      SETref_(ridge)= anotherridge;
 */
 #define SETref_(elem) (elem##p[-1])
 
 /*-----------------------------------------
 
    SETelem_(set, n)
      return the n'th element of set
 
    notes:
       assumes that n is valid [0..size] and that set is defined
       use SETelemt_() for type cast
 */
 #define SETelem_(set, n)           ((set)->e[n].p)
 
 /*-----------------------------------------
 
    SETelemt_(set, n, type)
      return the n'th element of set as a type
 
    notes:
       assumes that n is valid [0..size] and that set is defined
 */
 #define SETelemt_(set, n, type)    ((type*)((set)->e[n].p))
 
 /*-----------------------------------------
 
    SETelemaddr_(set, n, type)
      return address of the n'th element of a set
 
    notes:
       assumes that n is valid [0..size] and set is defined
 */
 #define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
 
 /*-----------------------------------------
 
    SETfirst_(set)
      return first element of set
 
 */
 #define SETfirst_(set)             ((set)->e[0].p)
 
 /*-----------------------------------------
 
    SETfirstt_(set, type)
      return first element of set as a type
 
 */
 #define SETfirstt_(set, type)      ((type*)((set)->e[0].p))
 
 /*-----------------------------------------
 
    SETsecond_(set)
      return second element of set
 
 */
 #define SETsecond_(set)            ((set)->e[1].p)
 
 /*-----------------------------------------
 
    SETsecondt_(set, type)
      return second element of set as a type
 */
 #define SETsecondt_(set, type)     ((type*)((set)->e[1].p))
 
 /*-----------------------------------------
 
    SETaddr_(set, type)
        return address of set's elements
 */
 #define SETaddr_(set,type)         ((type **)(&((set)->e[0].p)))
 
 /*-----------------------------------------
 
    SETreturnsize_(set, size)
      return size of a set
 
    notes:
       set must be defined
       use qh_setsize(set) unless speed is critical
 */
 #define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
 
 /*-----------------------------------------
 
    SETempty_(set)
      return true(1) if set is empty
 
    notes:
       set may be NULL
 */
 #define SETempty_(set)            (!set || (SETfirst_(set) ? 0 : 1))
 
 /*---------------------------------
 
   SETsizeaddr_(set)
     return pointer to 'actual size+1' of set (set CANNOT be NULL!!)
     Its type is setelemT* for strict aliasing
     All SETelemaddr_ must be cast to setelemT
 
 
   notes:
     *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
 */
 #define SETsizeaddr_(set) (&((set)->e[(set)->maxsize]))
 
 /*-----------------------------------------
 
    SETtruncate_(set, size)
      truncate set to size
 
    see:
      qh_settruncate()
 
 */
 #define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
       set->e[size].p= NULL;}
 
 /*======= prototypes in alphabetical order ============*/
 
 void  qh_setaddsorted(setT **setp, void *elem);
 void  qh_setaddnth(setT **setp, int nth, void *newelem);
 void  qh_setappend(setT **setp, void *elem);
 void  qh_setappend_set(setT **setp, setT *setA);
 void  qh_setappend2ndlast(setT **setp, void *elem);
 void  qh_setcheck(setT *set, const char *tname, unsigned id);
 void  qh_setcompact(setT *set);
 setT *qh_setcopy(setT *set, int extra);
 void *qh_setdel(setT *set, void *elem);
 void *qh_setdellast(setT *set);
 void *qh_setdelnth(setT *set, int nth);
 void *qh_setdelnthsorted(setT *set, int nth);
 void *qh_setdelsorted(setT *set, void *newelem);
 setT *qh_setduplicate( setT *set, int elemsize);
 void **qh_setendpointer(setT *set);
 int   qh_setequal(setT *setA, setT *setB);
 int   qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB);
 int   qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB);
 void  qh_setfree(setT **set);
 void  qh_setfree2( setT **setp, int elemsize);
 void  qh_setfreelong(setT **set);
 int   qh_setin(setT *set, void *setelem);
 int   qh_setindex(setT *set, void *setelem);
 void  qh_setlarger(setT **setp);
 void *qh_setlast(setT *set);
 setT *qh_setnew(int size);
 setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
 void  qh_setprint(FILE *fp, const char* string, setT *set);
 void  qh_setreplace(setT *set, void *oldelem, void *newelem);
 int   qh_setsize(setT *set);
 setT *qh_settemp(int setsize);
 void  qh_settempfree(setT **set);
 void  qh_settempfree_all(void);
 setT *qh_settemppop(void);
 void  qh_settemppush(setT *set);
 void  qh_settruncate(setT *set, int size);
 int   qh_setunique(setT **set, void *elem);
 void  qh_setzero(setT *set, int idx, int size);
 
 
 #endif /* qhDEFset */
diff --git a/src/libqhull/random.h b/src/libqhull/random.h
index c992cf1..76e08cb 100644
--- a/src/libqhull/random.h
+++ b/src/libqhull/random.h
@@ -1,34 +1,34 @@
 /*
  ---------------------------------
 
   random.h
     header file for random routines
 
    see qh-geom.htm and random.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/random.h#3 $$Change: 1464 $
-   $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/random.h#5 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFrandom
 #define qhDEFrandom 1
 
 #include "libqhull.h"
 
 /*============= prototypes in alphabetical order ======= */
 
 
 int     qh_argv_to_command(int argc, char *argv[], char* command, int max_size);
 int     qh_argv_to_command_size(int argc, char *argv[]);
 int     qh_rand( void);
 void    qh_srand( int seed);
 realT   qh_randomfactor(realT scale, realT offset);
 void    qh_randommatrix(realT *buffer, int dim, realT **row);
 int     qh_strtol(const char *s, char **endp);
 double  qh_strtod(const char *s, char **endp);
 
 #endif /* qhDEFrandom */
 
 
 
diff --git a/src/libqhull/stat.c b/src/libqhull/stat.c
index 771a62c..e0e4074 100644
--- a/src/libqhull/stat.c
+++ b/src/libqhull/stat.c
@@ -1,716 +1,716 @@
 /*
  ---------------------------------
 
    stat.c
    contains all statistics that are collected for qhull
 
    see qh-stat.htm and stat.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/stat.c#4 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/stat.c#6 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_a.h"
 
 /*============ global data structure ==========*/
 
 #if qh_QHpointer
 qhstatT *qh_qhstat=NULL;  /* global data structure */
 #else
 qhstatT qh_qhstat;   /* add "={0}" if this causes a compiler error */
 #endif
 
 /*========== functions in alphabetic order ================*/
 
 /*---------------------------------
 
   qh_allstatA()
     define statistics in groups of 20
 
   notes:
     (otherwise, 'gcc -O2' uses too much memory)
     uses qhstat.next
 */
 void qh_allstatA(void) {
 
    /* zdef_(type,name,doc,average) */
   zzdef_(zdoc, Zdoc2, "precision statistics", -1);
   zdef_(zinc, Znewvertex, NULL, -1);
   zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet(!0s)", Znewvertex);
   zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
   zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
   zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
   zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
 
   qhstat precision= qhstat next;  /* call qh_precision for each of these */
   zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);
   zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
   zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
   zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
   zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
   zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
   zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);
   zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
   zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
   zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
   zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);
 }
 void qh_allstatB(void) {
   zzdef_(zdoc, Zdoc1, "summary information", -1);
   zdef_(zinc, Zvertices, "number of vertices in output", -1);
   zdef_(zinc, Znumfacets, "number of facets in output", -1);
   zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
   zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);
   zdef_(zinc, Znumridges, "number of ridges in output", -1);
   zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
   zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
   zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
   zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
   zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
   zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
   zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
   zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
   zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
   zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
   zzdef_(zinc, Zsetplane, "facets created altogether", -1);
   zdef_(zinc, Ztotridges, "ridges created altogether", -1);
   zdef_(zinc, Zpostfacets, "facets before post merge", -1);
   zdef_(zadd, Znummergetot, "average merges per facet(at most 511)", Znumfacets);
   zdef_(zmax, Znummergemax, "  maximum merges for a facet(at most 511)", -1);
   zdef_(zinc, Zangle, NULL, -1);
   zdef_(wadd, Wangle, "average angle(cosine) of facet normals for all ridges", Zangle);
   zdef_(wmax, Wanglemax, "  maximum angle(cosine) of facet normals across a ridge", -1);
   zdef_(wmin, Wanglemin, "  minimum angle(cosine) of facet normals across a ridge", -1);
   zdef_(wadd, Wareatot, "total area of facets", -1);
   zdef_(wmax, Wareamax, "  maximum facet area", -1);
   zdef_(wmin, Wareamin, "  minimum facet area", -1);
 }
 void qh_allstatC(void) {
   zdef_(zdoc, Zdoc9, "build hull statistics", -1);
   zzdef_(zinc, Zprocessed, "points processed", -1);
   zzdef_(zinc, Zretry, "retries due to precision problems", -1);
   zdef_(wmax, Wretrymax, "  max. random joggle", -1);
   zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
   zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
   zdef_(zinc, Zinsidevisible, "  ave. visible facets without an horizon neighbor", Zprocessed);
   zdef_(zadd, Zvisfacettot,  "  ave. facets deleted per iteration", Zprocessed);
   zdef_(zmax, Zvisfacetmax,  "    maximum", -1);
   zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
   zdef_(zmax, Zvisvertexmax, "    maximum", -1);
   zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
   zdef_(zadd, Znewfacettot,  "ave. new or merged facets per iteration", Zprocessed);
   zdef_(zmax, Znewfacetmax,  "    maximum(includes initial simplex)", -1);
   zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
   zdef_(wadd, Wnewbalance2, "  standard deviation", -1);
   zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
   zdef_(wadd, Wpbalance2, "  standard deviation", -1);
   zdef_(zinc, Zpbalance, "  number of trials", -1);
   zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
   zdef_(zinc, Zdetsimplex, "determinants computed(area & initial hull)", -1);
   zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);
   zdef_(zinc, Znotmax, "points ignored(!above max_outside)", -1);
   zdef_(zinc, Znotgood, "points ignored(!above a good facet)", -1);
   zdef_(zinc, Znotgoodnew, "points ignored(didn't create a good new facet)", -1);
   zdef_(zinc, Zgoodfacet, "good facets found", -1);
   zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
   zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
   zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
   zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
 }
 void qh_allstatD(void) {
   zdef_(zinc, Zvisit, "resets of visit_id", -1);
   zdef_(zinc, Zvvisit, "  resets of vertex_visit", -1);
   zdef_(zmax, Zvisit2max, "  max visit_id/2", -1);
   zdef_(zmax, Zvvisit2max, "  max vertex_visit/2", -1);
 
   zdef_(zdoc, Zdoc4, "partitioning statistics(see previous for outer planes)", -1);
   zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
   zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
   zdef_(zinc, Zfindbest, "calls to findbest", -1);
   zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
   zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
   zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
   zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
   zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
   zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
   zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
   zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
   zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
   zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
   zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
   zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
   zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);
   zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
   zdef_(zinc, Zpartflip, "  repartitioned coplanar points for flipped orientation", -1);
 }
 void qh_allstatE(void) {
   zdef_(zinc, Zpartinside, "inside points", -1);
   zdef_(zinc, Zpartnear, "  inside points kept with a facet", -1);
   zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
   zdef_(zinc, Zbestlower, "calls to findbestlower", -1);
   zdef_(zinc, Zbestlowerv, "  with search of vertex neighbors", -1);
   zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
   zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
   zdef_(zinc, Ztotpartition, "partitions of a point", -1);
   zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
   zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
   zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
   zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
   zdef_(zinc, Zdistio, "distance tests for output", -1);
   zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
   zdef_(zinc, Zdistplane, "total number of distance tests", -1);
   zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
   zzdef_(zinc, Zpartcoplanar, "   distance tests for these partitions", -1);
   zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
 }
 void qh_allstatE2(void) {
   zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
   zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
   zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
   zdef_(zinc, Zhashridge, "total lookups of subridges(duplicates and boundary)", -1);
   zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
   zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
   zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);
 
   zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
   zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
   zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
   zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
   zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
   zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);
   zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
   zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);
   zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
 }
 void qh_allstatF(void) {
   zdef_(zdoc, Zdoc7, "statistics for merging", -1);
   zdef_(zinc, Zpremergetot, "merge iterations", -1);
   zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
   zdef_(zadd, Zmergeinitmax, "  maximum", -1);
   zdef_(zadd, Zmergesettot, "  ave. additional non-convex ridges per iteration", Zpremergetot);
   zdef_(zadd, Zmergesetmax, "  maximum additional in one pass", -1);
   zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
   zdef_(zadd, Zmergesettot2, "  additional non-convex ridges", -1);
   zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet(w/roundoff)", -1);
   zdef_(wmin, Wminvertex, "max distance of merged vertex below facet(or roundoff)", -1);
   zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);
   zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);
   zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);
   zdef_(zinc, Zmergesimplex, "merged a simplex", -1);
   zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);
   zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);
   zzdef_(zadd, Zcyclefacettot, "  ave. facets per cycle", Zcyclehorizon);
   zdef_(zmax, Zcyclefacetmax, "  max. facets", -1);
   zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
   zdef_(zinc, Zmergenew, "new facets merged", -1);
   zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
   zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
   zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);
   zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
   zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
   zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);
   zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);
 }
 void qh_allstatG(void) {
   zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
   zdef_(wadd, Wacoplanartot, "  average merge distance", Zacoplanar);
   zdef_(wmax, Wacoplanarmax, "  maximum merge distance", -1);
   zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
   zdef_(wadd, Wcoplanartot, "  average merge distance", Zcoplanar);
   zdef_(wmax, Wcoplanarmax, "  maximum merge distance", -1);
   zdef_(zinc, Zconcave, "merges due to concave facets", -1);
   zdef_(wadd, Wconcavetot, "  average merge distance", Zconcave);
   zdef_(wmax, Wconcavemax, "  maximum merge distance", -1);
   zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
   zdef_(wadd, Wavoidoldtot, "  average merge distance", Zavoidold);
   zdef_(wmax, Wavoidoldmax, "  maximum merge distance", -1);
   zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
   zdef_(wadd, Wdegentot, "  average merge distance", Zdegen);
   zdef_(wmax, Wdegenmax, "  maximum merge distance", -1);
   zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
   zdef_(wadd, Wflippedtot, "  average merge distance", Zflipped);
   zdef_(wmax, Wflippedmax, "  maximum merge distance", -1);
   zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);
   zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
   zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
 }
 void qh_allstatH(void) {
   zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);
   zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
   zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
   zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
   zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
   zdef_(zinc, Zdupridge, "  duplicate ridges detected", -1);
   zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
   zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
   zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);
   zdef_(zinc, Zdelfacetdup, "  facets deleted because of no neighbors", -1);
   zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
   zdef_(zinc, Zremvertexdel, "  deleted", -1);
   zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
   zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
   zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
   zdef_(zadd, Zintersecttot, "   ave. number found per vertex", Zintersect);
   zdef_(zmax, Zintersectmax, "   max. found for a vertex", -1);
   zdef_(zinc, Zvertexridge, NULL, -1);
   zdef_(zadd, Zvertexridgetot, "  ave. number of ridges per tested vertex", Zvertexridge);
   zdef_(zmax, Zvertexridgemax, "  max. number of ridges per tested vertex", -1);
 
   zdef_(zdoc, Zdoc10, "memory usage statistics(in bytes)", -1);
   zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
   zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
   zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1);
   zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
 } /* allstat */
 
 void qh_allstatI(void) {
   qhstat vridges= qhstat next;
   zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
   zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
   zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
   zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
   zzdef_(zinc, Zridgemid, "bounded ridges", -1);
   zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
   zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
   zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
   zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
   zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
   zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
   zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
   zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);
 
   zdef_(zdoc, Zdoc12, "Triangulation statistics(Qt)", -1);
   zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
   zdef_(zadd, Ztricoplanartot, "  ave. new facets created(may be deleted)", Ztricoplanar);
   zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
   zdef_(zinc, Ztrinull, "null new facets deleted(duplicated vertex)", -1);
   zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted(same vertices)", -1);
   zdef_(zinc, Ztridegen, "degenerate new facets in output(same ridge)", -1);
 } /* allstat */
 
 /*---------------------------------
 
   qh_allstatistics()
     reset printed flag for all statistics
 */
 void qh_allstatistics(void) {
   int i;
 
   for(i=ZEND; i--; )
     qhstat printed[i]= False;
 } /* allstatistics */
 
 #if qh_KEEPstatistics
 /*---------------------------------
 
   qh_collectstatistics()
     collect statistics for qh.facet_list
 
 */
 void qh_collectstatistics(void) {
   facetT *facet, *neighbor, **neighborp;
   vertexT *vertex, **vertexp;
   realT dotproduct, dist;
   int sizneighbors, sizridges, sizvertices, i;
 
   qh old_randomdist= qh RANDOMdist;
   qh RANDOMdist= False;
   zval_(Zmempoints)= qh num_points * qh normal_size +
                              sizeof(qhT) + sizeof(qhstatT);
   zval_(Zmemfacets)= 0;
   zval_(Zmemridges)= 0;
   zval_(Zmemvertices)= 0;
   zval_(Zangle)= 0;
   wval_(Wangle)= 0.0;
   zval_(Znumridges)= 0;
   zval_(Znumfacets)= 0;
   zval_(Znumneighbors)= 0;
   zval_(Znumvertices)= 0;
   zval_(Znumvneighbors)= 0;
   zval_(Znummergetot)= 0;
   zval_(Znummergemax)= 0;
   zval_(Zvertices)= qh num_vertices - qh_setsize(qh del_vertices);
   if (qh MERGING || qh APPROXhull || qh JOGGLEmax < REALmax/2)
     wmax_(Wmaxoutside, qh max_outside);
   if (qh MERGING)
     wmin_(Wminvertex, qh min_vertex);
   FORALLfacets
     facet->seen= False;
   if (qh DELAUNAY) {
     FORALLfacets {
       if (facet->upperdelaunay != qh UPPERdelaunay)
         facet->seen= True; /* remove from angle statistics */
     }
   }
   FORALLfacets {
     if (facet->visible && qh NEWfacets)
       continue;
     sizvertices= qh_setsize(facet->vertices);
     sizneighbors= qh_setsize(facet->neighbors);
     sizridges= qh_setsize(facet->ridges);
     zinc_(Znumfacets);
     zadd_(Znumvertices, sizvertices);
     zmax_(Zmaxvertices, sizvertices);
     zadd_(Znumneighbors, sizneighbors);
     zmax_(Zmaxneighbors, sizneighbors);
     zadd_(Znummergetot, facet->nummerge);
     i= facet->nummerge; /* avoid warnings */
     zmax_(Znummergemax, i);
     if (!facet->simplicial) {
       if (sizvertices == qh hull_dim) {
         zinc_(Znowsimplicial);
       }else {
         zinc_(Znonsimplicial);
       }
     }
     if (sizridges) {
       zadd_(Znumridges, sizridges);
       zmax_(Zmaxridges, sizridges);
     }
     zadd_(Zmemfacets, sizeof(facetT) + qh normal_size + 2*sizeof(setT)
        + SETelemsize * (sizneighbors + sizvertices));
     if (facet->ridges) {
       zadd_(Zmemridges,
          sizeof(setT) + SETelemsize * sizridges + sizridges *
          (sizeof(ridgeT) + sizeof(setT) + SETelemsize * (qh hull_dim-1))/2);
     }
     if (facet->outsideset)
       zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(facet->outsideset));
     if (facet->coplanarset)
       zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(facet->coplanarset));
     if (facet->seen) /* Delaunay upper envelope */
       continue;
     facet->seen= True;
     FOREACHneighbor_(facet) {
       if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
           || neighbor->seen || !facet->normal || !neighbor->normal)
         continue;
       dotproduct= qh_getangle(facet->normal, neighbor->normal);
       zinc_(Zangle);
       wadd_(Wangle, dotproduct);
       wmax_(Wanglemax, dotproduct)
       wmin_(Wanglemin, dotproduct)
     }
     if (facet->normal) {
       FOREACHvertex_(facet->vertices) {
         zinc_(Zdiststat);
         qh_distplane(vertex->point, facet, &dist);
         wmax_(Wvertexmax, dist);
         wmin_(Wvertexmin, dist);
       }
     }
   }
   FORALLvertices {
     if (vertex->deleted)
       continue;
     zadd_(Zmemvertices, sizeof(vertexT));
     if (vertex->neighbors) {
       sizneighbors= qh_setsize(vertex->neighbors);
       zadd_(Znumvneighbors, sizneighbors);
       zmax_(Zmaxvneighbors, sizneighbors);
       zadd_(Zmemvertices, sizeof(vertexT) + SETelemsize * sizneighbors);
     }
   }
   qh RANDOMdist= qh old_randomdist;
 } /* collectstatistics */
 #endif /* qh_KEEPstatistics */
 
 /*---------------------------------
 
   qh_freestatistics(  )
     free memory used for statistics
 */
 void qh_freestatistics(void) {
 
 #if qh_QHpointer
   qh_free(qh_qhstat);
   qh_qhstat= NULL;
 #endif
 } /* freestatistics */
 
 /*---------------------------------
 
   qh_initstatistics(  )
     allocate and initialize statistics
 
   notes:
     uses qh_malloc() instead of qh_memalloc() since mem.c not set up yet
     NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr  
     On first call, only qhmem.ferr is defined.  qh_memalloc is not setup.  
     Also invoked by QhullQh().
 */
 void qh_initstatistics(void) {
   int i;
   realT realx;
   int intx;
 
 #if qh_QHpointer
   if(qh_qhstat){  /* qh_initstatistics may be called from Qhull::resetStatistics() */
       qh_free(qh_qhstat);
       qh_qhstat= 0;
   }
   if (!(qh_qhstat= (qhstatT *)qh_malloc(sizeof(qhstatT)))) {
     fprintf(qhmem.ferr, "QH6183 qhull error (qh_initstatistics): insufficient memory\n");
     qh_exit(qh_ERRmem);  /* can not use qh_errexit() */
   }
 #endif
 
   qhstat next= 0;
   qh_allstatA();
   qh_allstatB();
   qh_allstatC();
   qh_allstatD();
   qh_allstatE();
   qh_allstatE2();
   qh_allstatF();
   qh_allstatG();
   qh_allstatH();
   qh_allstatI();
   if (qhstat next > (int)sizeof(qhstat id)) {
     qh_fprintf(qhmem.ferr, 6184, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\
       qhstat.next %d should be <= sizeof(qhstat id) %d\n", qhstat next, (int)sizeof(qhstat id));
 #if 0 /* for locating error, Znumridges should be duplicated */
     for(i=0; i < ZEND; i++) {
       int j;
       for(j=i+1; j < ZEND; j++) {
         if (qhstat id[i] == qhstat id[j]) {
           qh_fprintf(qhmem.ferr, 6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
               qhstat id[i], i, j);
         }
       }
     }
 #endif
     qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
   }
   qhstat init[zinc].i= 0;
   qhstat init[zadd].i= 0;
   qhstat init[zmin].i= INT_MAX;
   qhstat init[zmax].i= INT_MIN;
   qhstat init[wadd].r= 0;
   qhstat init[wmin].r= REALmax;
   qhstat init[wmax].r= -REALmax;
   for(i=0; i < ZEND; i++) {
     if (qhstat type[i] > ZTYPEreal) {
       realx= qhstat init[(unsigned char)(qhstat type[i])].r;
       qhstat stats[i].r= realx;
     }else if (qhstat type[i] != zdoc) {
       intx= qhstat init[(unsigned char)(qhstat type[i])].i;
       qhstat stats[i].i= intx;
     }
   }
 } /* initstatistics */
 
 /*---------------------------------
 
   qh_newstats(  )
     returns True if statistics for zdoc
 
   returns:
     next zdoc
 */
 boolT qh_newstats(int idx, int *nextindex) {
   boolT isnew= False;
   int start, i;
 
   if (qhstat type[qhstat id[idx]] == zdoc)
     start= idx+1;
   else
     start= idx;
   for(i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) {
     if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]])
         isnew= True;
   }
   *nextindex= i;
   return isnew;
 } /* newstats */
 
 /*---------------------------------
 
   qh_nostatistic( index )
     true if no statistic to print
 */
 boolT qh_nostatistic(int i) {
 
   if ((qhstat type[i] > ZTYPEreal
        &&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r)
       || (qhstat type[i] < ZTYPEreal
           &&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i))
     return True;
   return False;
 } /* nostatistic */
 
 #if qh_KEEPstatistics
 /*---------------------------------
 
   qh_printallstatistics( fp, string )
     print all statistics with header 'string'
 */
 void qh_printallstatistics(FILE *fp, const char *string) {
 
   qh_allstatistics();
   qh_collectstatistics();
   qh_printstatistics(fp, string);
   qh_memstatistics(fp);
 }
 
 
 /*---------------------------------
 
   qh_printstatistics( fp, string )
     print statistics to a file with header 'string'
     skips statistics with qhstat.printed[] (reset with qh_allstatistics)
 
   see:
     qh_printallstatistics()
 */
 void qh_printstatistics(FILE *fp, const char *string) {
   int i, k;
   realT ave;
 
   if (qh num_points != qh num_vertices) {
     wval_(Wpbalance)= 0;
     wval_(Wpbalance2)= 0;
   }else
     wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                  wval_(Wpbalance2), &ave);
   wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                  wval_(Wnewbalance2), &ave);
   qh_fprintf(fp, 9350, "\n\
 %s\n\
  qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh rbox_command,
      qh qhull_command, qh_version, qh qhull_options);
   qh_fprintf(fp, 9351, "\nprecision constants:\n\
  %6.2g max. abs. coordinate in the (transformed) input('Qbd:n')\n\
  %6.2g max. roundoff error for distance computation('En')\n\
  %6.2g max. roundoff error for angle computations\n\
  %6.2g min. distance for outside points ('Wn')\n\
  %6.2g min. distance for visible facets ('Vn')\n\
  %6.2g max. distance for coplanar facets ('Un')\n\
  %6.2g max. facet width for recomputing centrum and area\n\
 ",
   qh MAXabs_coord, qh DISTround, qh ANGLEround, qh MINoutside,
         qh MINvisible, qh MAXcoplanar, qh WIDEfacet);
   if (qh KEEPnearinside)
     qh_fprintf(fp, 9352, "\
  %6.2g max. distance for near-inside points\n", qh NEARinside);
   if (qh premerge_cos < REALmax/2) qh_fprintf(fp, 9353, "\
  %6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
   if (qh PREmerge) qh_fprintf(fp, 9354, "\
  %6.2g radius of pre-merge centrum\n", qh premerge_centrum);
   if (qh postmerge_cos < REALmax/2) qh_fprintf(fp, 9355, "\
  %6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
   if (qh POSTmerge) qh_fprintf(fp, 9356, "\
  %6.2g radius of post-merge centrum\n", qh postmerge_centrum);
   qh_fprintf(fp, 9357, "\
  %6.2g max. distance for merging two simplicial facets\n\
  %6.2g max. roundoff error for arithmetic operations\n\
  %6.2g min. denominator for divisions\n\
   zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom);
   for(k=0; k < qh hull_dim; k++)
     qh_fprintf(fp, 9358, "%6.2e ", qh NEARzero[k]);
   qh_fprintf(fp, 9359, "\n\n");
   for(i=0 ; i < qhstat next; )
     qh_printstats(fp, i, &i);
 } /* printstatistics */
 #endif /* qh_KEEPstatistics */
 
 /*---------------------------------
 
   qh_printstatlevel( fp, id )
     print level information for a statistic
 
   notes:
     nop if id >= ZEND, printed, or same as initial value
 */
 void qh_printstatlevel(FILE *fp, int id, int start) {
 #define NULLfield "       "
 
   if (id >= ZEND || qhstat printed[id])
     return;
   if (qhstat type[id] == zdoc) {
     qh_fprintf(fp, 9360, "%s\n", qhstat doc[id]);
     return;
   }
   start= 0; /* not used */
   if (qh_nostatistic(id) || !qhstat doc[id])
     return;
   qhstat printed[id]= True;
   if (qhstat count[id] != -1
       && qhstat stats[(unsigned char)(qhstat count[id])].i == 0)
     qh_fprintf(fp, 9361, " *0 cnt*");
   else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
     qh_fprintf(fp, 9362, "%7.2g", qhstat stats[id].r);
   else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
     qh_fprintf(fp, 9363, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
   else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
     qh_fprintf(fp, 9364, "%7d", qhstat stats[id].i);
   else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
     qh_fprintf(fp, 9365, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
   qh_fprintf(fp, 9366, " %s\n", qhstat doc[id]);
 } /* printstatlevel */
 
 
 /*---------------------------------
 
   qh_printstats( fp, index, nextindex )
     print statistics for a zdoc group
 
   returns:
     next zdoc if non-null
 */
 void qh_printstats(FILE *fp, int idx, int *nextindex) {
   int j, nexti;
 
   if (qh_newstats(idx, &nexti)) {
     qh_fprintf(fp, 9367, "\n");
     for (j=idx; j--------------------------------
 
   qh_stddev( num, tot, tot2, ave )
     compute the standard deviation and average from statistics
 
     tot2 is the sum of the squares
   notes:
     computes r.m.s.:
       (x-ave)^2
       == x^2 - 2x tot/num +   (tot/num)^2
       == tot2 - 2 tot tot/num + tot tot/num
       == tot2 - tot ave
 */
 realT qh_stddev(int num, realT tot, realT tot2, realT *ave) {
   realT stddev;
 
   *ave= tot/num;
   stddev= sqrt(tot2/num - *ave * *ave);
   return stddev;
 } /* stddev */
 
 #endif /* qh_KEEPstatistics */
 
 #if !qh_KEEPstatistics
 void    qh_collectstatistics(void) {}
 void    qh_printallstatistics(FILE *fp, char *string) {};
 void    qh_printstatistics(FILE *fp, char *string) {}
 #endif
 
diff --git a/src/libqhull/stat.h b/src/libqhull/stat.h
index da7f51b..6c1bd49 100644
--- a/src/libqhull/stat.h
+++ b/src/libqhull/stat.h
@@ -1,541 +1,541 @@
 /*
  ---------------------------------
 
    stat.h
      contains all statistics that are collected for qhull
 
    see qh-stat.htm and stat.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhull/stat.h#6 $$Change: 1645 $
-   $DateTime: 2014/01/15 12:51:30 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhull/stat.h#8 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    recompile qhull if you change this file
 
    Integer statistics are Z* while real statistics are W*.
 
    define maydebugx to call a routine at every statistic event
 
 */
 
 #ifndef qhDEFstat
 #define qhDEFstat 1
 
 #include "libqhull.h"
 
 /*---------------------------------
 
   qh_KEEPstatistics
     0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
 */
 #ifndef qh_KEEPstatistics
 #define qh_KEEPstatistics 1
 #endif
 
 /*---------------------------------
 
   Zxxx for integers, Wxxx for reals
 
   notes:
     be sure that all statistics are defined in stat.c
       otherwise initialization may core dump
     can pick up all statistics by:
       grep '[zw].*_[(][ZW]' *.c >z.x
     remove trailers with query">-
     remove leaders with  query-replace-regexp [ ^I]+  (
 */
 #if qh_KEEPstatistics
 enum qh_statistics {     /* alphabetical after Z/W */
     Zacoplanar,
     Wacoplanarmax,
     Wacoplanartot,
     Zangle,
     Wangle,
     Wanglemax,
     Wanglemin,
     Zangletests,
     Wareatot,
     Wareamax,
     Wareamin,
     Zavoidold,
     Wavoidoldmax,
     Wavoidoldtot,
     Zback0,
     Zbestcentrum,
     Zbestdist,
     Zbestlower,
     Zbestlowerv,
     Zcentrumtests,
     Zcheckpart,
     Zcomputefurthest,
     Zconcave,
     Wconcavemax,
     Wconcavetot,
     Zconcaveridges,
     Zconcaveridge,
     Zcoplanar,
     Wcoplanarmax,
     Wcoplanartot,
     Zcoplanarangle,
     Zcoplanarcentrum,
     Zcoplanarhorizon,
     Zcoplanarinside,
     Zcoplanarpart,
     Zcoplanarridges,
     Wcpu,
     Zcyclefacetmax,
     Zcyclefacettot,
     Zcyclehorizon,
     Zcyclevertex,
     Zdegen,
     Wdegenmax,
     Wdegentot,
     Zdegenvertex,
     Zdelfacetdup,
     Zdelridge,
     Zdelvertextot,
     Zdelvertexmax,
     Zdetsimplex,
     Zdistcheck,
     Zdistconvex,
     Zdistgood,
     Zdistio,
     Zdistplane,
     Zdiststat,
     Zdistvertex,
     Zdistzero,
     Zdoc1,
     Zdoc2,
     Zdoc3,
     Zdoc4,
     Zdoc5,
     Zdoc6,
     Zdoc7,
     Zdoc8,
     Zdoc9,
     Zdoc10,
     Zdoc11,
     Zdoc12,
     Zdropdegen,
     Zdropneighbor,
     Zdupflip,
     Zduplicate,
     Wduplicatemax,
     Wduplicatetot,
     Zdupridge,
     Zdupsame,
     Zflipped,
     Wflippedmax,
     Wflippedtot,
     Zflippedfacets,
     Zfindbest,
     Zfindbestmax,
     Zfindbesttot,
     Zfindcoplanar,
     Zfindfail,
     Zfindhorizon,
     Zfindhorizonmax,
     Zfindhorizontot,
     Zfindjump,
     Zfindnew,
     Zfindnewmax,
     Zfindnewtot,
     Zfindnewjump,
     Zfindnewsharp,
     Zgauss0,
     Zgoodfacet,
     Zhashlookup,
     Zhashridge,
     Zhashridgetest,
     Zhashtests,
     Zinsidevisible,
     Zintersect,
     Zintersectfail,
     Zintersectmax,
     Zintersectnum,
     Zintersecttot,
     Zmaxneighbors,
     Wmaxout,
     Wmaxoutside,
     Zmaxridges,
     Zmaxvertex,
     Zmaxvertices,
     Zmaxvneighbors,
     Zmemfacets,
     Zmempoints,
     Zmemridges,
     Zmemvertices,
     Zmergeflipdup,
     Zmergehorizon,
     Zmergeinittot,
     Zmergeinitmax,
     Zmergeinittot2,
     Zmergeintohorizon,
     Zmergenew,
     Zmergesettot,
     Zmergesetmax,
     Zmergesettot2,
     Zmergesimplex,
     Zmergevertex,
     Wmindenom,
     Wminvertex,
     Zminnorm,
     Zmultiridge,
     Znearlysingular,
     Zneighbor,
     Wnewbalance,
     Wnewbalance2,
     Znewfacettot,
     Znewfacetmax,
     Znewvertex,
     Wnewvertex,
     Wnewvertexmax,
     Znoarea,
     Znonsimplicial,
     Znowsimplicial,
     Znotgood,
     Znotgoodnew,
     Znotmax,
     Znumfacets,
     Znummergemax,
     Znummergetot,
     Znumneighbors,
     Znumridges,
     Znumvertices,
     Znumvisibility,
     Znumvneighbors,
     Zonehorizon,
     Zpartangle,
     Zpartcoplanar,
     Zpartflip,
     Zparthorizon,
     Zpartinside,
     Zpartition,
     Zpartitionall,
     Zpartnear,
     Zpbalance,
     Wpbalance,
     Wpbalance2,
     Zpostfacets,
     Zpremergetot,
     Zprocessed,
     Zremvertex,
     Zremvertexdel,
     Zrenameall,
     Zrenamepinch,
     Zrenameshare,
     Zretry,
     Wretrymax,
     Zridge,
     Wridge,
     Wridgemax,
     Zridge0,
     Wridge0,
     Wridge0max,
     Zridgemid,
     Wridgemid,
     Wridgemidmax,
     Zridgeok,
     Wridgeok,
     Wridgeokmax,
     Zsearchpoints,
     Zsetplane,
     Ztestvneighbor,
     Ztotcheck,
     Ztothorizon,
     Ztotmerge,
     Ztotpartcoplanar,
     Ztotpartition,
     Ztotridges,
     Ztotvertices,
     Ztotvisible,
     Ztricoplanar,
     Ztricoplanarmax,
     Ztricoplanartot,
     Ztridegen,
     Ztrimirror,
     Ztrinull,
     Wvertexmax,
     Wvertexmin,
     Zvertexridge,
     Zvertexridgetot,
     Zvertexridgemax,
     Zvertices,
     Zvisfacettot,
     Zvisfacetmax,
     Zvisit,
     Zvisit2max,
     Zvisvertextot,
     Zvisvertexmax,
     Zvvisit,
     Zvvisit2max,
     Zwidefacet,
     Zwidevertices,
     ZEND};
 
 /*---------------------------------
 
   Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
 
   notes:
     be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
 */
 #else
 enum qh_statistics {     /* for zzdef etc. macros */
   Zback0,
   Zbestdist,
   Zcentrumtests,
   Zcheckpart,
   Zconcaveridges,
   Zcoplanarhorizon,
   Zcoplanarpart,
   Zcoplanarridges,
   Zcyclefacettot,
   Zcyclehorizon,
   Zdelvertextot,
   Zdistcheck,
   Zdistconvex,
   Zdistzero,
   Zdoc1,
   Zdoc2,
   Zdoc3,
   Zdoc11,
   Zflippedfacets,
   Zgauss0,
   Zminnorm,
   Zmultiridge,
   Znearlysingular,
   Wnewvertexmax,
   Znumvisibility,
   Zpartcoplanar,
   Zpartition,
   Zpartitionall,
   Zprocessed,
   Zretry,
   Zridge,
   Wridge,
   Wridgemax,
   Zridge0,
   Wridge0,
   Wridge0max,
   Zridgemid,
   Wridgemid,
   Wridgemidmax,
   Zridgeok,
   Wridgeok,
   Wridgeokmax,
   Zsetplane,
   Ztotcheck,
   Ztotmerge,
     ZEND};
 #endif
 
 /*---------------------------------
 
   ztype
     the type of a statistic sets its initial value.
 
   notes:
     The type should be the same as the macro for collecting the statistic
 */
 enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
 
 /*========== macros and constants =============*/
 
 /*----------------------------------
 
   MAYdebugx
     define as maydebug() to be called frequently for error trapping
 */
 #define MAYdebugx
 
 /*----------------------------------
 
   zzdef_, zdef_( type, name, doc, -1)
     define a statistic (assumes 'qhstat.next= 0;')
 
   zdef_( type, name, doc, count)
     define an averaged statistic
     printed as name/count
 */
 #define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
    qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
 #if qh_KEEPstatistics
 #define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
    qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
 #else
 #define zdef_(type,name,doc,count)
 #endif
 
 /*----------------------------------
 
   zzinc_( name ), zinc_( name)
     increment an integer statistic
 */
 #define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
 #if qh_KEEPstatistics
 #define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
 #else
 #define zinc_(id) {}
 #endif
 
 /*----------------------------------
 
   zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
     add value to an integer or real statistic
 */
 #define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
 #define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
 #if qh_KEEPstatistics
 #define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
 #define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
 #else
 #define zadd_(id, val) {}
 #define wadd_(id, val) {}
 #endif
 
 /*----------------------------------
 
   zzval_( name ), zval_( name ), wwval_( name )
     set or return value of a statistic
 */
 #define zzval_(id) ((qhstat stats[id]).i)
 #define wwval_(id) ((qhstat stats[id]).r)
 #if qh_KEEPstatistics
 #define zval_(id) ((qhstat stats[id]).i)
 #define wval_(id) ((qhstat stats[id]).r)
 #else
 #define zval_(id) qhstat tempi
 #define wval_(id) qhstat tempr
 #endif
 
 /*----------------------------------
 
   zmax_( id, val ), wmax_( id, value )
     maximize id with val
 */
 #define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
 #if qh_KEEPstatistics
 #define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
 #define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
 #else
 #define zmax_(id, val) {}
 #define wmax_(id, val) {}
 #endif
 
 /*----------------------------------
 
   zmin_( id, val ), wmin_( id, value )
     minimize id with val
 */
 #if qh_KEEPstatistics
 #define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
 #define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
 #else
 #define zmin_(id, val) {}
 #define wmin_(id, val) {}
 #endif
 
 /*================== stat.h types ==============*/
 
 
 /*----------------------------------
 
   intrealT
     union of integer and real, used for statistics
 */
 typedef union intrealT intrealT;    /* union of int and realT */
 union intrealT {
     int i;
     realT r;
 };
 
 /*----------------------------------
 
   qhstat
     global data structure for statistics, similar to qh and qhrbox
 
   notes:
    access to qh_qhstat is via the "qhstat" macro.  There are two choices
    qh_QHpointer = 1     access globals via a pointer
                         enables qh_saveqhull() and qh_restoreqhull()
                 = 0     qh_qhstat is a static data structure
                         only one instance of qhull() can be active at a time
                         default value
    qh_QHpointer is defined in libqhull.h
    qh_QHpointer_dllimport and qh_dllimport define qh_qh as __declspec(dllimport) [libqhull.h]
 
    allocated in stat.c using qh_malloc()
 */
 #ifndef DEFqhstatT
 #define DEFqhstatT 1
 typedef struct qhstatT qhstatT;
 #endif
 
 #if qh_QHpointer_dllimport
 #define qhstat qh_qhstat->
 __declspec(dllimport) extern qhstatT *qh_qhstat;
 #elif qh_QHpointer
 #define qhstat qh_qhstat->
 extern qhstatT *qh_qhstat;
 #elif qh_dllimport
 #define qhstat qh_qhstat.
 __declspec(dllimport) extern qhstatT qh_qhstat;
 #else
 #define qhstat qh_qhstat.
 extern qhstatT qh_qhstat;
 #endif
 struct qhstatT {
   intrealT   stats[ZEND];     /* integer and real statistics */
   unsigned   char id[ZEND+10]; /* id's in print order */
   const char *doc[ZEND];       /* array of documentation strings */
   short int  count[ZEND];     /* -1 if none, else index of count to use */
   char       type[ZEND];      /* type, see ztypes above */
   char       printed[ZEND];   /* true, if statistic has been printed */
   intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
 
   int        next;            /* next index for zdef_ */
   int        precision;       /* index for precision problems */
   int        vridges;         /* index for Voronoi ridges */
   int        tempi;
   realT      tempr;
 };
 
 /*========== function prototypes ===========*/
 
 void    qh_allstatA(void);
 void    qh_allstatB(void);
 void    qh_allstatC(void);
 void    qh_allstatD(void);
 void    qh_allstatE(void);
 void    qh_allstatE2(void);
 void    qh_allstatF(void);
 void    qh_allstatG(void);
 void    qh_allstatH(void);
 void    qh_allstatI(void);
 void    qh_allstatistics(void);
 void    qh_collectstatistics(void);
 void    qh_freestatistics(void);
 void    qh_initstatistics(void);
 boolT   qh_newstats(int idx, int *nextindex);
 boolT   qh_nostatistic(int i);
 void    qh_printallstatistics(FILE *fp, const char *string);
 void    qh_printstatistics(FILE *fp, const char *string);
 void    qh_printstatlevel(FILE *fp, int id, int start);
 void    qh_printstats(FILE *fp, int idx, int *nextindex);
 realT   qh_stddev(int num, realT tot, realT tot2, realT *ave);
 
 #endif   /* qhDEFstat */
diff --git a/src/libqhullcpp/Coordinates.cpp b/src/libqhullcpp/Coordinates.cpp
index 522b45c..d71e0c9 100644
--- a/src/libqhullcpp/Coordinates.cpp
+++ b/src/libqhullcpp/Coordinates.cpp
@@ -1,184 +1,184 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/Coordinates.cpp#7 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/Coordinates.cpp#8 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "functionObjects.h"
 #include "QhullError.h"
 #include "Coordinates.h"
 
 #include 
 #include 
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//! Coordinates -- vector of coordT (normally double)
 
 #//Element access
 
 // Inefficient without result-value-optimization or implicitly shared object
 Coordinates Coordinates::
 mid(countT idx, countT length) const
 {
     countT newLength= length;
     if(length<0 || idx+length > count()){
         newLength= count()-idx;
     }
     Coordinates result;
     if(newLength>0){
         std::copy(begin()+idx, begin()+(idx+newLength), std::back_inserter(result));
     }
     return result;
 }//mid
 
 coordT Coordinates::
 value(countT idx, const coordT &defaultValue) const
 {
     return ((idx < 0 || idx >= count()) ? defaultValue : (*this)[idx]);
 }//value
 
 #//!\name GetSet
 
 Coordinates Coordinates::
 operator+(const Coordinates &other) const
 {
     Coordinates result(*this);
     std::copy(other.begin(), other.end(), std::back_inserter(result));
     return result;
 }//operator+
 
 Coordinates & Coordinates::
 operator+=(const Coordinates &other)
 {
     if(&other==this){
         Coordinates clone(other);
         std::copy(clone.begin(), clone.end(), std::back_inserter(*this));
     }else{
         std::copy(other.begin(), other.end(), std::back_inserter(*this));
     }
     return *this;
 }//operator+=
 
 #//Read-write
 
 coordT Coordinates::
 takeAt(countT idx)
 {
     coordT c= at(idx);
     erase(begin()+idx);
     return c;
 }//takeAt
 
 coordT Coordinates::
 takeLast()
 {
     coordT c= last();
     removeLast();
     return c;
 }//takeLast
 
 void Coordinates::
 swap(countT idx, countT other)
 {
     coordT c= at(idx);
     at(idx)= at(other);
     at(other)= c;
 }//swap
 
 #//Search
 
 bool Coordinates::
 contains(const coordT &t) const
 {
     CoordinatesIterator i(*this);
     return i.findNext(t);
 }//contains
 
 countT Coordinates::
 count(const coordT &t) const
 {
     CoordinatesIterator i(*this);
     countT result= 0;
     while(i.findNext(t)){
         ++result;
     }
     return result;
 }//count
 
 countT Coordinates::
 indexOf(const coordT &t, countT from) const
 {
     if(from<0){
         from += count();
         if(from<0){
             from= 0;
         }
     }
     if(from(i-begin())); // WARN64 coordinate index
             }
             ++i;
         }
     }
     return -1;
 }//indexOf
 
 countT Coordinates::
 lastIndexOf(const coordT &t, countT from) const
 {
     if(from<0){
         from += count();
     }else if(from>=count()){
         from= count()-1;
     }
     if(from>=0){
         const_iterator i= begin()+from+1;
         while(i-- != constBegin()){
             if(*i==t){
                 return (static_cast(i-begin())); // WARN64 coordinate index
             }
         }
     }
     return -1;
 }//lastIndexOf
 
 void Coordinates::
 removeAll(const coordT &t)
 {
     MutableCoordinatesIterator i(*this);
     while(i.findNext(t)){
         i.remove();
     }
 }//removeAll
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::istream;
 using std::ostream;
 using std::string;
 using std::ws;
 using orgQhull::Coordinates;
 
 ostream &
 operator<<(ostream &os, const Coordinates &cs)
 {
     Coordinates::const_iterator c= cs.begin();
     for(countT i=cs.count(); i--; ){
         os << *c++ << " ";
     }
     return os;
 }//operator<<
 
diff --git a/src/libqhullcpp/Coordinates.h b/src/libqhullcpp/Coordinates.h
index b30183c..63af70f 100644
--- a/src/libqhullcpp/Coordinates.h
+++ b/src/libqhullcpp/Coordinates.h
@@ -1,305 +1,305 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/Coordinates.h#10 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/Coordinates.h#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHCOORDINATES_H
 #define QHCOORDINATES_H
 
 #include "QhullError.h"
 #include "QhullIterator.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 
 #include  // ptrdiff_t, size_t
 #include 
 // Requires STL vector class.  Can use with another vector class such as QList.
 #include 
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! An std::vector of point coordinates independent of dimension
     //! Used by PointCoordinates for RboxPoints
     //! A QhullPoint refers to previously allocated coordinates
     class Coordinates;
     class MutableCoordinatesIterator;
 
 class Coordinates {
 
 private:
 #//!\name Fields
     std::vector coordinate_array;
 
 public:
 #//!\name Subtypes
 
     class const_iterator;
     class iterator;
     typedef iterator Iterator;
     typedef const_iterator ConstIterator;
 
     typedef coordT              value_type;
     typedef const value_type   *const_pointer;
     typedef const value_type &  const_reference;
     typedef value_type *        pointer;
     typedef value_type &        reference;
     typedef ptrdiff_t           difference_type;
     typedef countT              size_type;
 
 #//!\name Construct
                         Coordinates() {};
     explicit            Coordinates(const std::vector &other) : coordinate_array(other) {}
                         Coordinates(const Coordinates &other) : coordinate_array(other.coordinate_array) {}
     Coordinates &       operator=(const Coordinates &other) { coordinate_array= other.coordinate_array; return *this; }
     Coordinates &       operator=(const std::vector &other) { coordinate_array= other; return *this; }
                         ~Coordinates() {}
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const { return coordinate_array; }
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList       toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     countT              count() const { return static_cast(size()); }
     coordT *            data() { return isEmpty() ? 0 : &at(0); }
     const coordT *      data() const { return const_cast(isEmpty() ? 0 : &at(0)); }
     bool                isEmpty() const { return coordinate_array.empty(); }
     bool                operator==(const Coordinates &other) const  { return coordinate_array==other.coordinate_array; }
     bool                operator!=(const Coordinates &other) const  { return coordinate_array!=other.coordinate_array; }
     size_t              size() const { return coordinate_array.size(); }
 
 #//!\name Element access
     coordT &            at(countT idx) { return coordinate_array.at(idx); }
     const coordT &      at(countT idx) const { return coordinate_array.at(idx); }
     coordT &            back() { return coordinate_array.back(); }
     const coordT &      back() const { return coordinate_array.back(); }
     coordT &            first() { return front(); }
     const coordT &      first() const { return front(); }
     coordT &            front() { return coordinate_array.front(); }
     const coordT &      front() const { return coordinate_array.front(); }
     coordT &            last() { return back(); }
     const coordT &      last() const { return back(); }
     Coordinates         mid(countT idx, countT length= -1) const; //!<\todo countT -1 indicates 
     coordT &            operator[](countT idx) { return coordinate_array.operator[](idx); }
     const coordT &      operator[](countT idx) const { return coordinate_array.operator[](idx); }
     coordT              value(countT idx, const coordT &defaultValue) const;
 
 #//!\name Iterator
     iterator            begin() { return iterator(coordinate_array.begin()); }
     const_iterator      begin() const { return const_iterator(coordinate_array.begin()); }
     const_iterator      constBegin() const { return begin(); }
     const_iterator      constEnd() const { return end(); }
     iterator            end() { return iterator(coordinate_array.end()); }
     const_iterator      end() const { return const_iterator(coordinate_array.end()); }
 
 #//!\name GetSet
     Coordinates         operator+(const Coordinates &other) const;
 
 #//!\name Modify
     void                append(const coordT &c) { push_back(c); }
     void                clear() { coordinate_array.clear(); }
     iterator            erase(iterator idx) { return iterator(coordinate_array.erase(idx.base())); }
     iterator            erase(iterator beginIterator, iterator endIterator) { return iterator(coordinate_array.erase(beginIterator.base(), endIterator.base())); }
     void                insert(countT before, const coordT &c) { insert(begin()+before, c); }
     iterator            insert(iterator before, const coordT &c) { return iterator(coordinate_array.insert(before.base(), c)); }
     void                move(countT from, countT to) { insert(to, takeAt(from)); }
     Coordinates &       operator+=(const Coordinates &other);
     Coordinates &       operator+=(const coordT &c) { append(c); return *this; }
     Coordinates &       operator<<(const Coordinates &other) { return *this += other; }
     Coordinates &       operator<<(const coordT &c) { return *this += c; }
     void                pop_back() { coordinate_array.pop_back(); }
     void                pop_front() { removeFirst(); }
     void                prepend(const coordT &c) { insert(begin(), c); }
     void                push_back(const coordT &c) { coordinate_array.push_back(c); }
     void                push_front(const coordT &c) { insert(begin(), c); }
                         //removeAll below
     void                removeAt(countT idx) { erase(begin()+idx); }
     void                removeFirst() { erase(begin()); }
     void                removeLast() { erase(--end()); }
     void                replace(countT idx, const coordT &c) { (*this)[idx]= c; }
     void                reserve(countT i) { coordinate_array.reserve(i); }
     void                swap(countT idx, countT other);
     coordT              takeAt(countT idx);
     coordT              takeFirst() { return takeAt(0); }
     coordT              takeLast();
 
 #//!\name Search
     bool                contains(const coordT &t) const;
     countT              count(const coordT &t) const;
     countT              indexOf(const coordT &t, countT from = 0) const;
     countT              lastIndexOf(const coordT &t, countT from = -1) const;
     void                removeAll(const coordT &t);
 
 #//!\name Coordinates::iterator -- from QhullPoints, forwarding to coordinate_array
     // before const_iterator for conversion with comparison operators
     class iterator {
 
     private:
         std::vector::iterator i;
         friend class const_iterator;
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef coordT      value_type;
         typedef value_type *pointer;
         typedef value_type &reference;
         typedef ptrdiff_t   difference_type;
 
                         iterator() {}
                         iterator(const iterator &other) { i= other.i; }
         explicit        iterator(const std::vector::iterator &vi) { i= vi; }
         iterator &      operator=(const iterator &other) { i= other.i; return *this; }
         std::vector::iterator &base() { return i; }
                         // No operator-> for base types
         coordT &        operator*() const { return *i; }
         coordT &        operator[](countT idx) const { return i[idx]; }
 
         bool            operator==(const iterator &other) const { return i==other.i; }
         bool            operator!=(const iterator &other) const { return i!=other.i; }
         bool            operator<(const iterator &other) const { return i(const iterator &other) const { return i>other.i; }
         bool            operator>=(const iterator &other) const { return i>=other.i; }
               // reinterpret_cast to break circular dependency
         bool            operator==(const Coordinates::const_iterator &other) const { return *this==reinterpret_cast(other); }
         bool            operator!=(const Coordinates::const_iterator &other) const { return *this!=reinterpret_cast(other); }
         bool            operator<(const Coordinates::const_iterator &other) const { return *this(other); }
         bool            operator<=(const Coordinates::const_iterator &other) const { return *this<=reinterpret_cast(other); }
         bool            operator>(const Coordinates::const_iterator &other) const { return *this>reinterpret_cast(other); }
         bool            operator>=(const Coordinates::const_iterator &other) const { return *this>=reinterpret_cast(other); }
 
         iterator        operator++() { return iterator(++i); } //FIXUP QH11012 Should return reference, but get reference to temporary
         iterator        operator++(int) { return iterator(i++); }
         iterator        operator--() { return iterator(--i); }
         iterator        operator--(int) { return iterator(i--); }
         iterator        operator+=(countT idx) { return iterator(i += idx); }
         iterator        operator-=(countT idx) { return iterator(i -= idx); }
         iterator        operator+(countT idx) const { return iterator(i+idx); }
         iterator        operator-(countT idx) const { return iterator(i-idx); }
         difference_type operator-(iterator other) const { return i-other.i; }
     };//Coordinates::iterator
 
 #//!\name Coordinates::const_iterator
     class const_iterator {
 
     private:
         std::vector::const_iterator i;
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef coordT            value_type;
         typedef const value_type *pointer;
         typedef const value_type &reference;
         typedef ptrdiff_t         difference_type;
 
                         const_iterator() {}
                         const_iterator(const const_iterator &other) { i= other.i; }
                         const_iterator(iterator o) : i(o.i) {}
         explicit        const_iterator(const std::vector::const_iterator &vi) { i= vi; }
         const_iterator &operator=(const const_iterator &other) { i= other.i; return *this; }
                         // No operator-> for base types
                         // No reference to a base type for () and []
         const coordT &  operator*() const { return *i; }
         const coordT &  operator[](countT idx) const { return i[idx]; }
 
         bool            operator==(const const_iterator &other) const { return i==other.i; }
         bool            operator!=(const const_iterator &other) const { return i!=other.i; }
         bool            operator<(const const_iterator &other) const { return i(const const_iterator &other) const { return i>other.i; }
         bool            operator>=(const const_iterator &other) const { return i>=other.i; }
 
         const_iterator  operator++() { return const_iterator(++i); } //FIXUP QH11014 -- too much copying
         const_iterator  operator++(int) { return const_iterator(i++); }
         const_iterator  operator--() { return const_iterator(--i); }
         const_iterator  operator--(int) { return const_iterator(i--); }
         const_iterator  operator+=(countT idx) { return const_iterator(i += idx); }
         const_iterator  operator-=(countT idx) { return const_iterator(i -= idx); }
         const_iterator  operator+(countT idx) const { return const_iterator(i+idx); }
         const_iterator  operator-(countT idx) const { return const_iterator(i-idx); }
         difference_type operator-(const_iterator other) const { return i-other.i; }
     };//Coordinates::const_iterator
 
 };//Coordinates
 
 //class CoordinatesIterator
 //QHULL_DECLARE_SEQUENTIAL_ITERATOR(Coordinates, coordT)
 
 class CoordinatesIterator
 {
     typedef Coordinates::const_iterator const_iterator;
 
 private:
     const Coordinates * c;
     const_iterator      i;
 
 public:
                         CoordinatesIterator(const Coordinates &container): c(&container), i(c->constBegin()) {}
     CoordinatesIterator &operator=(const Coordinates &container) { c= &container; i= c->constBegin(); return *this; }
                         ~CoordinatesIterator() {}
 
     bool                findNext(const coordT &t) { while (i != c->constEnd()) if(*i++ == t){ return true;} return false; }
     bool                findPrevious(const coordT &t) { while (i != c->constBegin())if (*(--i) == t){ return true;} return false;  }
     bool                hasNext() const { return i != c->constEnd(); }
     bool                hasPrevious() const { return i != c->constBegin(); }
     const coordT &      next() { return *i++; }
     const coordT &      previous() { return *--i; }
     const coordT &      peekNext() const { return *i; }
     const coordT &      peekPrevious() const { const_iterator p= i; return *--p; }
     void                toFront() { i= c->constBegin(); }
     void                toBack() { i= c->constEnd(); }
 };//CoordinatesIterator
 
 //class MutableCoordinatesIterator
 //QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Coordinates, coordT)
 class MutableCoordinatesIterator
 {
     typedef Coordinates::iterator iterator;
     typedef Coordinates::const_iterator const_iterator;
 
 private:
     Coordinates *       c;
     iterator            i;
     iterator            n;
     bool                item_exists() const { return const_iterator(n) != c->constEnd(); }
 
 public:
                         MutableCoordinatesIterator(Coordinates &container) : c(&container) { i= c->begin(); n= c->end(); }
     MutableCoordinatesIterator &operator=(Coordinates &container) { c= &container; i= c->begin(); n= c->end(); return *this; }
                         ~MutableCoordinatesIterator() {}
 
     bool                findNext(const coordT &t) { while(c->constEnd()!=const_iterator(n= i)){ if(*i++==t){ return true;}} return false; }
     bool                findPrevious(const coordT &t) { while(c->constBegin()!=const_iterator(i)){ if(*(n= --i)== t){ return true;}} n= c->end(); return false;  }
     bool                hasNext() const { return (c->constEnd()!=const_iterator(i)); }
     bool                hasPrevious() const { return (c->constBegin()!=const_iterator(i)); }
     void                insert(const coordT &t) { n= i= c->insert(i, t); ++i; }
     coordT &            next() { n= i++; return *n; }
     coordT &            peekNext() const { return *i; }
     coordT &            peekPrevious() const { iterator p= i; return *--p; }
     coordT &            previous() { n= --i; return *n; }
     void                remove() { if(c->constEnd()!=const_iterator(n)){ i= c->erase(n); n= c->end();} }
     void                setValue(const coordT &t) const { if(c->constEnd()!=const_iterator(n)){ *n= t;} }
     void                toFront() { i= c->begin(); n= c->end(); }
     void                toBack() { i= c->end(); n= i; }
     coordT &            value() { QHULL_ASSERT(item_exists()); return *n; }
     const coordT &      value() const { QHULL_ASSERT(item_exists()); return *n; }
 };//MutableCoordinatesIterator
 
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::Coordinates &c);
 
 #endif // QHCOORDINATES_H
diff --git a/src/libqhullcpp/PointCoordinates.cpp b/src/libqhullcpp/PointCoordinates.cpp
index be57c60..c24c92f 100644
--- a/src/libqhullcpp/PointCoordinates.cpp
+++ b/src/libqhullcpp/PointCoordinates.cpp
@@ -1,342 +1,342 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/PointCoordinates.cpp#11 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/PointCoordinates.cpp#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullError.h"
 #include "QhullPoint.h"
 #include "PointCoordinates.h"
 
 #include 
 #include 
 
 using std::istream;
 using std::string;
 using std::ws;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//! PointCoordinates -- vector of PointCoordinates
 
 #//!\name Constructors
 
 //! Qhull and QhullQh constructors are the same
 PointCoordinates::
 PointCoordinates(const Qhull &q)
 : QhullPoints(q)
 , point_coordinates()
 , describe_points()
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(const Qhull &q, int pointDimension)
 : QhullPoints(q, pointDimension)
 , point_coordinates()
 , describe_points()
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(const Qhull &q, const std::string &aComment)
 : QhullPoints(q)
 , point_coordinates()
 , describe_points(aComment)
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment)
 : QhullPoints(q, pointDimension)
 , point_coordinates()
 , describe_points(aComment)
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c)
 : QhullPoints(q, pointDimension)
 , point_coordinates()
 , describe_points(aComment)
 {
     append(coordinatesCount, c);
 }
 
 PointCoordinates::
 PointCoordinates(QhullQh *qh)
 : QhullPoints(qh)
 , point_coordinates()
 , describe_points()
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(QhullQh *qh, int pointDimension)
 : QhullPoints(qh, pointDimension)
 , point_coordinates()
 , describe_points()
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(QhullQh *qh, const std::string &aComment)
 : QhullPoints(qh)
 , point_coordinates()
 , describe_points(aComment)
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(QhullQh *qh, int pointDimension, const std::string &aComment)
 : QhullPoints(qh, pointDimension)
 , point_coordinates()
 , describe_points(aComment)
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(QhullQh *qh, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c)
 : QhullPoints(qh, pointDimension)
 , point_coordinates()
 , describe_points(aComment)
 {
     append(coordinatesCount, c);
 }
 
 PointCoordinates::
 PointCoordinates(const PointCoordinates &other)
 : QhullPoints(other)
 , point_coordinates(other.point_coordinates)
 , describe_points(other.describe_points)
 {
     makeValid();  // Update point_first and point_end
 }
 
 PointCoordinates & PointCoordinates::
 operator=(const PointCoordinates &other)
 {
     QhullPoints::operator=(other);
     point_coordinates= other.point_coordinates;
     describe_points= other.describe_points;
     makeValid(); // Update point_first and point_end
     return *this;
 }//operator=
 
 PointCoordinates::
 ~PointCoordinates()
 { }
 
 #//!\name GetSet
 
 void PointCoordinates::
 checkValid() const
 {
     if(getCoordinates().data()!=data()
     || getCoordinates().count()!=coordinateCount()){
         throw QhullError(10060, "Qhull error: first point (%x) is not PointCoordinates.data() or count (%d) is not PointCoordinates.count (%d)", coordinateCount(), getCoordinates().count(), 0.0, data());
     }
 }//checkValid
 
 void PointCoordinates::
 setDimension(int i)
 {
     if(i<0){
         throw QhullError(10062, "Qhull error: can not set PointCoordinates dimension to %d", i);
     }
     int currentDimension=QhullPoints::dimension();
     if(currentDimension!=0 && i!=currentDimension){
         throw QhullError(10063, "Qhull error: can not change PointCoordinates dimension (from %d to %d)", currentDimension, i);
     }
     QhullPoints::setDimension(i);
 }//setDimension
 
 #//!\name Foreach
 
 Coordinates::ConstIterator PointCoordinates::
 beginCoordinates(countT pointIndex) const
 {
     return point_coordinates.begin()+indexOffset(pointIndex);
 }
 
 Coordinates::Iterator PointCoordinates::
 beginCoordinates(countT pointIndex)
 {
     return point_coordinates.begin()+indexOffset(pointIndex);
 }
 
 #//!\name Methods
 
 void PointCoordinates::
 append(countT coordinatesCount, const coordT *c)
 {
     if(coordinatesCount<=0){
         return;
     }
     if(includesCoordinates(c)){
         throw QhullError(10065, "Qhull error: can not append a subset of PointCoordinates to itself.  The coordinates for point %d may move.", indexOf(c, QhullError::NOthrow));
     }
     reserveCoordinates(coordinatesCount);
     std::copy(c, c+coordinatesCount, std::back_inserter(point_coordinates));
     makeValid();
 }//append coordT
 
 void PointCoordinates::
 append(const PointCoordinates &other)
 {
     setDimension(other.dimension());
     append(other.coordinateCount(), other.data());
 }//append PointCoordinates
 
 void PointCoordinates::
 append(const QhullPoint &p)
 {
     setDimension(p.dimension());
     append(p.dimension(), p.coordinates());
 }//append QhullPoint
 
 void PointCoordinates::
 appendComment(const std::string &s){
     if(char c= s[0] && describe_points.empty()){
         if(c=='-' || isdigit(c)){
             throw QhullError(10028, "Qhull argument error: comments can not start with a number or minus, %s", 0, 0, 0.0, s.c_str());
         }
     }
     describe_points += s;
 }//appendComment
 
 //! Read PointCoordinates from istream.  First two numbers are dimension and count.  A non-digit starts a rboxCommand.
 //! Overwrites describe_points.  See qh_readpoints [io.c]
 void PointCoordinates::
 appendPoints(istream &in)
 {
     int inDimension;
     countT inCount;
     in >> ws >> inDimension >> ws;
     if(!in.good()){
         in.clear();
         string remainder;
         getline(in, remainder);
         throw QhullError(10005, "Qhull error: input did not start with dimension or count -- %s", 0, 0, 0, remainder.c_str());
     }
     char c= (char)in.peek();
     if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
         getline(in, describe_points);
         in >> ws;
     }
     in >> inCount >> ws;
     if(!in.good()){
         in.clear();
         string remainder;
         getline(in, remainder);
         throw QhullError(10009, "Qhull error: input did not start with dimension and count -- %d %s", inDimension, 0, 0, remainder.c_str());
     }
     c= (char)in.peek();
     if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
         getline(in, describe_points);
         in >> ws;
     }
     if(inCount> p >> ws;
         if(in.fail()){
             in.clear();
             string remainder;
             getline(in, remainder);
             throw QhullError(10008, "Qhull error: failed to read coordinate %d  of point %d\n   %s", coordinatesCount % inDimension, coordinatesCount/inDimension, 0, remainder.c_str());
         }else{
             point_coordinates.push_back(p);
             coordinatesCount++;
         }
     }
     if(coordinatesCount != inCount*inDimension){
         if(coordinatesCount%inDimension==0){
             throw QhullError(10006, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates", int(inCount), inDimension, 0.0, int(coordinatesCount/inDimension));
         }else{
             throw QhullError(10012, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates plus %f extra coordinates", inCount, inDimension, float(coordinatesCount%inDimension), coordinatesCount/inDimension);
         }
     }
     makeValid();
 }//appendPoints istream
 
 PointCoordinates PointCoordinates::
 operator+(const PointCoordinates &other) const
 {
     PointCoordinates pc= *this;
     pc << other;
     return pc;
 }//operator+
 
 void PointCoordinates::
 reserveCoordinates(countT newCoordinates)
 {
     // vector::reserve is not const
     point_coordinates.reserve((countT)point_coordinates.size()+newCoordinates); // WARN64
     makeValid();
 }//reserveCoordinates
 
 #//Helpers
 
 countT PointCoordinates::
 indexOffset(countT i) const {
     countT n= i*dimension();
     countT coordinatesCount= point_coordinates.count();
     if(i<0 || n>coordinatesCount){
         throw QhullError(10061, "Qhull error: point_coordinates is too short (%d) for point %d", coordinatesCount, i);
     }
     return n;
 }
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 
 using orgQhull::Coordinates;
 using orgQhull::PointCoordinates;
 
 ostream&
 operator<<(ostream &os, const PointCoordinates &p)
 {
     p.checkValid();
     countT count= p.count();
     int dimension= p.dimension();
     string comment= p.comment();
     if(comment.empty()){
         os << dimension << endl;
     }else{
         os << dimension << " " << comment << endl;
     }
     os << count << endl;
     Coordinates::ConstIterator c= p.beginCoordinates();
     for(countT i=0; i
 #include 
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! Zero or more QhullPoints with Coordinates and description
     class PointCoordinates;
 
 class PointCoordinates : public QhullPoints {
 
 private:
 #//!\name Fields
     Coordinates         point_coordinates;      //! std::vector of point coordinates
                                                 //! may have extraCoordinates()
     std::string         describe_points;          //! Comment describing PointCoordinates
 
 public:
 #//!\name Construct
     explicit            PointCoordinates(const Qhull &q);
                         PointCoordinates(const Qhull &q, int pointDimension);
                         PointCoordinates(const Qhull &q, const std::string &aComment);
                         PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment);
                         PointCoordinates(const Qhull &q, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c); // may be invalid
                         //! Use append() and appendPoints() for Coordinates and vector
     explicit            PointCoordinates(QhullQh *qh);
                         PointCoordinates(QhullQh *qh, int pointDimension);
                         PointCoordinates(QhullQh *qh, const std::string &aComment);
                         PointCoordinates(QhullQh *qh, int pointDimension, const std::string &aComment);
                         PointCoordinates(QhullQh *qh, int pointDimension, const std::string &aComment, countT coordinatesCount, const coordT *c); // may be invalid
                         //! Use append() and appendPoints() for Coordinates and vector
                         PointCoordinates(const PointCoordinates &other);
     PointCoordinates &  operator=(const PointCoordinates &other);
                         ~PointCoordinates();
 
 #//!\name Convert
     //! QhullPoints coordinates, constData, data, count, size
 #ifndef QHULL_NO_STL
     void                append(const std::vector &otherCoordinates) { if(!otherCoordinates.empty()){ append((int)otherCoordinates.size(), &otherCoordinates[0]); } }
     std::vector toStdVector() const { return point_coordinates.toStdVector(); }
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     void                append(const QList &pointCoordinates) { if(!pointCoordinates.isEmpty()){ append(pointCoordinates.count(), &pointCoordinates[0]); } }
     QList       toQList() const { return point_coordinates.toQList(); }
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     //! See QhullPoints for coordinates, coordinateCount, dimension, empty, isEmpty, ==, !=
     void                checkValid() const;
     std::string         comment() const { return describe_points; }
     void                makeValid() { defineAs(point_coordinates.count(), point_coordinates.data()); }
     const Coordinates & getCoordinates() const { return point_coordinates; }
     void                setComment(const std::string &s) { describe_points= s; }
     void                setDimension(int i);
 
 private:
     void                defineAs(countT coordinatesCount, coordT *c) { QhullPoints::defineAs(coordinatesCount, c); }
     //! defineAs() otherwise disabled
 public:
 
 #//!\name ElementAccess
     //! See QhullPoints for at, back, first, front, last, mid, [], value
 
 #//!\name Foreach
     //! See QhullPoints for begin, constBegin, end
     Coordinates::ConstIterator  beginCoordinates() const { return point_coordinates.begin(); }
     Coordinates::Iterator       beginCoordinates() { return point_coordinates.begin(); }
     Coordinates::ConstIterator  beginCoordinates(countT pointIndex) const;
     Coordinates::Iterator       beginCoordinates(countT pointIndex);
     Coordinates::ConstIterator  endCoordinates() const { return point_coordinates.end(); }
     Coordinates::Iterator       endCoordinates() { return point_coordinates.end(); }
 
 #//!\name Search
     //! See QhullPoints for contains, count, indexOf, lastIndexOf
 
 #//!\name GetSet
     PointCoordinates    operator+(const PointCoordinates &other) const;
 
 #//!\name Modify
     //FIXUP QH11001: Add clear() and other modify operators from Coordinates.h.  Include QhullPoint::operator=()
     void                append(countT coordinatesCount, const coordT *c);  //! Dimension previously defined
     void                append(const coordT &c) { append(1, &c); } //! Dimension previously defined
     void                append(const QhullPoint &p);
     //! See convert for std::vector and QList
     void                append(const Coordinates &c) { append(c.count(), c.data()); }
     void                append(const PointCoordinates &other);
     void                appendComment(const std::string &s);
     void                appendPoints(std::istream &in);
     PointCoordinates &  operator+=(const PointCoordinates &other) { append(other); return *this; }
     PointCoordinates &  operator+=(const coordT &c) { append(c); return *this; }
     PointCoordinates &  operator+=(const QhullPoint &p) { append(p); return *this; }
     PointCoordinates &  operator<<(const PointCoordinates &other) { return *this += other; }
     PointCoordinates &  operator<<(const coordT &c) { return *this += c; }
     PointCoordinates &  operator<<(const QhullPoint &p) { return *this += p; }
     // reserve() is non-const
     void                reserveCoordinates(countT newCoordinates);
 
 #//!\name Helpers
 private:
     int                 indexOffset(int i) const;
 
 };//PointCoordinates
 
 // No references to QhullPoint.  Prevents use of QHULL_DECLARE_SEQUENTIAL_ITERATOR(PointCoordinates, QhullPoint)
 class PointCoordinatesIterator
 {
     typedef PointCoordinates::const_iterator const_iterator;
 
 private:
     const PointCoordinates *c;
     const_iterator      i;
 
 public:
                         PointCoordinatesIterator(const PointCoordinates &container) : c(&container), i(c->constBegin()) {}
                         PointCoordinatesIterator &operator=(const PointCoordinates &container) { c = &container; i = c->constBegin(); return *this; }
 
     void                toFront() { i = c->constBegin(); }
     void                toBack() { i = c->constEnd(); }
     bool                hasNext() const { return i != c->constEnd(); }
     const QhullPoint    next() { return *i++; }
     const QhullPoint    peekNext() const { return *i; }
     bool                hasPrevious() const { return i != c->constBegin(); }
     const QhullPoint    previous() { return *--i; }
     const QhullPoint    peekPrevious() const { const_iterator p = i; return *--p; }
     bool                findNext(const QhullPoint &t) { while(i != c->constEnd()){ if (*i++ == t) return true;} return false; }
     bool                findPrevious(const QhullPoint &t) { while(i != c->constBegin()){ if (*(--i) == t) return true;} return false;  }
 };//CoordinatesIterator
 
 // FIXUP QH11002:  Add MutablePointCoordinatesIterator after adding modify operators
 \
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &          operator<<(std::ostream &os, const orgQhull::PointCoordinates &p);
 
 #endif // QHPOINTCOORDINATES_H
diff --git a/src/libqhullcpp/Qhull.cpp b/src/libqhullcpp/Qhull.cpp
index aaf2cbd..ab243be 100644
--- a/src/libqhullcpp/Qhull.cpp
+++ b/src/libqhullcpp/Qhull.cpp
@@ -1,313 +1,313 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/Qhull.cpp#15 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/Qhull.cpp#16 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! Qhull -- invoke qhull from C++
 #//! Compile libqhull and Qhull together due to use of setjmp/longjmp()
 
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullQh.h"
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "Qhull.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 using std::cerr;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//Global variables
 
 const char s_unsupported_options[]=" Fd TI ";
 const char s_not_output_options[]= " Fd TI A C d E H P Qb QbB Qbb Qc Qf Qg Qi Qm QJ Qr QR Qs Qt Qv Qx Qz Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 R Tc TC TM TP TR Tv TV TW U v V W ";
 
 #//Constructor, destructor, etc.
 Qhull::
 Qhull()
 : qh_qh(0)
 , origin_point()
 , run_called(false)
 , feasiblePoint()
 {
     allocateQhullQh();
 }//Qhull
 
 //! Invokes Qhull on rboxPoints 
 //! Same as runQhull()
 //! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
 //! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
 Qhull::
 Qhull(const RboxPoints &rboxPoints, const char *qhullCommand2)
 : qh_qh(0)
 , origin_point()
 , run_called(false)
 , feasiblePoint()
 {
     allocateQhullQh();
     runQhull(rboxPoints, qhullCommand2);
 }//Qhull rbox
 
 //! Invokes Qhull on a set of input points
 //! Same as runQhull()
 //! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
 Qhull::
 Qhull(const char *inputComment, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2)
 : qh_qh(0)
 , origin_point()
 , run_called(false)
 , feasiblePoint()
 {
     allocateQhullQh();
     runQhull(inputComment, pointDimension, pointCount, pointCoordinates, qhullCommand2);
 }//Qhull points
 
 void Qhull::
 allocateQhullQh()
 {
     qh_qh= new QhullQh;
     if(qh_qh!=static_cast(qh_qh)){
         throw QhullError(10074, "Qhull error: QhullQh at a different address than base type QhT (%d bytes).  Please report compiler to qhull.org", (int)(static_cast(qh_qh)-qh_qh));
     }
 }//allocateQhullQh
 
 Qhull::
 ~Qhull() throw()
 {
     // Except for cerr, does not throw errors
     if(qh_qh->hasQhullMessage()){
         cerr<< "\nQhull output at end\n"; //FIXUP QH11005: where should error and log messages go on ~Qhull?
         cerr<< qh_qh->qhullMessage();
         qh_qh->clearQhullMessage();
     }
     delete qh_qh;
     qh_qh= 0;
 }//~Qhull
 
 #//!\name GetSet
 
 void Qhull::
 checkIfQhullInitialized()
 {
     if(!initialized()){ // qh_initqhull_buffers() not called
         throw QhullError(10023, "Qhull error: checkIfQhullInitialized failed.  Call runQhull() first.");
     }
 }//checkIfQhullInitialized
 
 #//GetValue
 
 double Qhull::
 area(){
     checkIfQhullInitialized();
     if(!qh_qh->hasAreaVolume){
         QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
             qh_getarea(qh_qh, qh_qh->facet_list);
         }
         qh_qh->maybeThrowQhullMessage(QH_TRY_status);
     }
     return qh_qh->totarea;
 }//area
 
 double Qhull::
 volume(){
     checkIfQhullInitialized();
     if(!qh_qh->hasAreaVolume){
         QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
             qh_getarea(qh_qh, qh_qh->facet_list);
         }
         qh_qh->maybeThrowQhullMessage(QH_TRY_status);
     }
     return qh_qh->totvol;
 }//volume
 
 #//!\name Foreach
 
 //! Define QhullVertex::neighborFacets().
 //! Automatically called if merging facets or computing the Voronoi diagram.
 //! Noop if called multiple times.
 void Qhull::
 defineVertexNeighborFacets(){
     checkIfQhullInitialized();
     if(!qh_qh->hasAreaVolume){
         QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
             qh_vertexneighbors(qh_qh);
         }
         qh_qh->maybeThrowQhullMessage(QH_TRY_status);
     }
 }//defineVertexNeighborFacets
 
 QhullFacetList Qhull::
 facetList() const{
     return QhullFacetList(beginFacet(), endFacet());
 }//facetList
 
 QhullPoints Qhull::
 points() const
 {
     return QhullPoints(qh_qh, qh_qh->hull_dim, qh_qh->num_points*qh_qh->hull_dim, qh_qh->first_point);
 }//points
 
 QhullPointSet Qhull::
 otherPoints() const
 {
     return QhullPointSet(qh_qh, qh_qh->other_points);
 }//otherPoints
 
 //! Return vertices of the convex hull.
 QhullVertexList Qhull::
 vertexList() const{
     return QhullVertexList(beginVertex(), endVertex());
 }//vertexList
 
 #//!\name Methods
 
 void Qhull::
 outputQhull()
 {
     checkIfQhullInitialized();
     QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
         qh_produce_output2(qh_qh);
     }
     qh_qh->maybeThrowQhullMessage(QH_TRY_status);
 }//outputQhull
 
 void Qhull::
 outputQhull(const char *outputflags)
 {
     checkIfQhullInitialized();
     string cmd(" "); // qh_checkflags skips first word
     cmd += outputflags;
     char *command= const_cast(cmd.c_str());
     QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
         qh_clear_outputflags(qh_qh);
         char *s = qh_qh->qhull_command + strlen(qh_qh->qhull_command) + 1; //space
         strncat(qh_qh->qhull_command, command, sizeof(qh_qh->qhull_command)-strlen(qh_qh->qhull_command)-1);
         qh_checkflags(qh_qh, command, const_cast(s_not_output_options));
         qh_initflags(qh_qh, s);
         qh_initqhull_outputflags(qh_qh);
         if(qh_qh->KEEPminArea < REALmax/2
            || (0 != qh_qh->KEEParea + qh_qh->KEEPmerge + qh_qh->GOODvertex
                     + qh_qh->GOODthreshold + qh_qh->GOODpoint + qh_qh->SPLITthresholds)){
             facetT *facet;
             qh_qh->ONLYgood= False;
             FORALLfacet_(qh_qh->facet_list) {
                 facet->good= True;
             }
             qh_prepare_output(qh_qh);
         }
         qh_produce_output2(qh_qh);
         if(qh_qh->VERIFYoutput && !qh_qh->STOPpoint && !qh_qh->STOPcone){
             qh_check_points(qh_qh);
         }
     }
     qh_qh->maybeThrowQhullMessage(QH_TRY_status);
 }//outputQhull
 
 //! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
 void Qhull::
 runQhull(const RboxPoints &rboxPoints, const char *qhullCommand2)
 {
     runQhull(rboxPoints.comment().c_str(), rboxPoints.dimension(), rboxPoints.count(), &*rboxPoints.coordinates(), qhullCommand2);
 }//runQhull, RboxPoints
 
 //! pointCoordinates is a array of points, input sites ('d' or 'v'), or halfspaces with offset last ('H')
 //! Derived from qh_new_qhull [user.c]
 //! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
 //! For qhull commands, see http://www.qhull.org/html/qhull.htm or html/qhull.htm
 void Qhull::
 runQhull(const char *inputComment, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2)
 {
     if(run_called){
         throw QhullError(10027, "Qhull error: runQhull called twice.  Only one call allowed.");
     }
     run_called= true;
     string s("qhull ");
     s += qhullCommand2;
     char *command= const_cast(s.c_str());
     /* FIXUP
     int QH_TRY_status; 
     if(qh_qh->NOerrexit){ 
         qh_qh->NOerrexit= False; 
         QH_TRY_status= setjmp(qh_qh->errexit); 
     }else{ 
     QH_TRY_status= QH_TRY_ERROR; 
     } 
     if(!QH_TRY_status){ 
 */
     QH_TRY_(qh_qh){ // no object creation -- destructors are skipped on longjmp()
         qh_checkflags(qh_qh, command, const_cast(s_unsupported_options));
         qh_initflags(qh_qh, command);
         *qh_qh->rbox_command= '\0';
         strncat( qh_qh->rbox_command, inputComment, sizeof(qh_qh->rbox_command)-1);
         if(qh_qh->DELAUNAY){
             qh_qh->PROJECTdelaunay= True;   // qh_init_B() calls qh_projectinput()
         }
         pointT *newPoints= const_cast(pointCoordinates);
         int newDimension= pointDimension;
         int newIsMalloc= False;
         if(qh_qh->HALFspace){
             --newDimension;
             initializeFeasiblePoint(newDimension);
             newPoints= qh_sethalfspace_all(qh_qh, pointDimension, pointCount, newPoints, qh_qh->feasible_point);
             newIsMalloc= True;
         }
         qh_init_B(qh_qh, newPoints, pointCount, newDimension, newIsMalloc);
         qh_qhull(qh_qh);
         qh_check_output(qh_qh);
         qh_prepare_output(qh_qh);
         if(qh_qh->VERIFYoutput && !qh_qh->STOPpoint && !qh_qh->STOPcone){
             qh_check_points(qh_qh);
         }
     }
     for(int k= qh_qh->hull_dim; k--; ){  // Do not move into QH_TRY block.  It may throw an error
         origin_point << 0.0;
     }
     qh_qh->maybeThrowQhullMessage(QH_TRY_status);
 }//runQhull
 
 #//Helpers -- be careful of allocating C++ objects due to setjmp/longjmp() error handling by qh_... routines
 
 void Qhull::
 initializeFeasiblePoint(int hulldim)
 {
     if(qh_qh->feasible_string){
         qh_setfeasible(qh_qh, hulldim);
     }else{
         if(feasiblePoint.isEmpty()){
             qh_fprintf(qh_qh, qh_qh->ferr, 6209, "qhull error: missing feasible point for halfspace intersection.  Use option 'Hn,n' or set qh_qh.feasiblePoint\n");
             qh_errexit(qh_qh, qh_ERRmem, NULL, NULL);
         }
         if(feasiblePoint.size()!=(size_t)hulldim){
             qh_fprintf(qh_qh, qh_qh->ferr, 6210, "qhull error: dimension of feasiblePoint should be %d.  It is %u", hulldim, feasiblePoint.size());
             qh_errexit(qh_qh, qh_ERRmem, NULL, NULL);
         }
         if (!(qh_qh->feasible_point= (coordT*)qh_malloc(hulldim * sizeof(coordT)))) {
             qh_fprintf(qh_qh, qh_qh->ferr, 6202, "qhull error: insufficient memory for feasible point\n");
             qh_errexit(qh_qh, qh_ERRmem, NULL, NULL);
         }
         coordT *t= qh_qh->feasible_point;
         // No qh_... routines after here -- longjmp() ignores destructor
         for(Coordinates::ConstIterator p=feasiblePoint.begin(); p.  It could be rewritten for another vector class such as QList
    #define QHULL_USES_QT
       Supply conversions to QT
       qhulltest requires QT.  It is defined in RoadTest.h
 
   #define QHULL_ASSERT
       Defined by QhullError.h
       It invokes assert()
 */
 
 #//!\name Used here
     class QhullFacetList;
     class QhullPoints;
     class QhullQh;
     class RboxPoints;
 
 #//!\name Defined here
     class Qhull;
 
 //! Interface to Qhull from C++
 class Qhull {
 
 private:
 #//!\name Members and friends
     QhullQh *           qh_qh;          //! qhT for this instance
     Coordinates         origin_point;   //! origin for qh_qh->hull_dim.  Set by runQhull()
     bool                run_called;     //! True at start of runQhull.  Errors if call again.
 
 #//!\name Attribute
 public:
     Coordinates         feasiblePoint;  //! feasible point for half-space intersection
     // FIXUP QH11003 feasiblePoint useOutputStream as field or getter?
 
 #//!\name Constructors
                         Qhull();      //!< call Qhull::runQhull() next
                         Qhull(const RboxPoints &rboxPoints, const char *qhullCommand2);
                         Qhull(const char *inputComment, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2);
                         ~Qhull() throw();
 private:                // Disable copy constructor and assignment.  Qhull owns QhullQh.
                         Qhull(const Qhull &);
     Qhull               &operator=(const Qhull &);
 
 private:
     void                allocateQhullQh();
 
 public:
 
 #//!\name GetSet
     void                checkIfQhullInitialized();
     int                 dimension() const { return qh_qh->input_dim; } //!< Dimension of input and result
     countT              facetCount() const { return qh_qh->num_facets; }
     int                 hullDimension() const { return qh_qh->hull_dim; } //!< Dimension of the computed hull
     bool                initialized() const { return (qh_qh->hull_dim>0); }
     const char *        inputComment() const { return qh_qh->rbox_command; }
     //! non-const due to QhullPoint
     QhullPoint          origin() { QHULL_ASSERT(initialized()); return QhullPoint(qh_qh, origin_point.data()); }
     QhullQh *           qh() const { return qh_qh; };
     const char *        qhullCommand() const { return qh_qh->qhull_command; }
     const char *        rboxCommand() const { return qh_qh->rbox_command; }
     countT              vertexCount() const { return qh_qh->num_vertices; }
 
 #//!\name GetEpsilon
     double              angleEpsilon() const { return qh_qh->angleEpsilon(); } //!< Epsilon for hyperplane angle equality
     double              distanceEpsilon() const { return qh_qh->distanceEpsilon(); } //!< Epsilon for distance to hyperplane
     double              factorEpsilon() const { return qh_qh->factorEpsilon(); }  //!< Factor for angleEpsilon and distanceEpsilon
     void                setFactorEpsilon(double a) { qh_qh->setFactorEpsilon(a); }
 
 #//!\name ForEach
     QhullFacet          beginFacet() const { return QhullFacet(qh_qh, qh_qh->facet_list); }
     QhullVertex         beginVertex() const { return QhullVertex(qh_qh, qh_qh->vertex_list); }
     void                defineVertexNeighborFacets(); //!< Automatically called if merging facets or Voronoi diagram
     QhullFacet          endFacet() const { return QhullFacet(qh_qh, qh_qh->facet_tail); }
     QhullVertex         endVertex() const { return QhullVertex(qh_qh, qh_qh->vertex_tail); }
     QhullFacetList      facetList() const;
     QhullFacet          firstFacet() const { return beginFacet(); }
     QhullVertex         firstVertex() const { return beginVertex(); }
     QhullPoints         points() const;
     QhullPointSet       otherPoints() const;
                         //! Same as points().coordinates()
     coordT *            pointCoordinateBegin() const { return qh_qh->first_point; }
     coordT *            pointCoordinateEnd() const { return qh_qh->first_point + qh_qh->num_points*qh_qh->hull_dim; }
     QhullVertexList     vertexList() const;
 
 #//!\name Methods
     double              area();
     void                checkAndFreeQhullMemory() { qh_qh->checkAndFreeQhullMemory(); }
     void                outputQhull();
     void                outputQhull(const char * outputflags);
     void                runQhull(const RboxPoints &rboxPoints, const char *qhullCommand2);
     void                runQhull(const char *inputComment, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2);
     double              volume();
 
 #//!\name Helpers
 private:
     void                initializeFeasiblePoint(int hulldim);
 };//Qhull
 
 }//namespace orgQhull
 
 #endif // QHULLCPP_H
diff --git a/src/libqhullcpp/QhullError.h b/src/libqhullcpp/QhullError.h
index da39d3a..56b6079 100644
--- a/src/libqhullcpp/QhullError.h
+++ b/src/libqhullcpp/QhullError.h
@@ -1,62 +1,62 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullError.h#11 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullError.h#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLERROR_H
 #define QHULLERROR_H
 
 #include "RoadError.h"
 // No dependencies on libqhull
 
 #ifndef QHULL_ASSERT
 #define QHULL_ASSERT assert
 #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! QhullError -- std::exception class for Qhull
     class QhullError;
 
 class QhullError : public RoadError {
 
 public:
 #//!\name Constants
     enum {
         QHULLfirstError= 10000, //MSG_QHULL_ERROR in Qhull's user.h
         QHULLlastError= 10076,
         NOthrow= 1 //! For flag to UsingLibQhull()
     };
 
 #//!\name Constructors
     // default constructors
     QhullError() : RoadError() {};
     QhullError(const QhullError &other) : RoadError(other) {}
     QhullError(int code, const std::string &message) : RoadError(code, message) {};
     QhullError(int code, const char *fmt) : RoadError(code, fmt) {};
     QhullError(int code, const char *fmt, int d) : RoadError(code, fmt, d) {};
     QhullError(int code, const char *fmt, int d, int d2) : RoadError(code, fmt, d, d2) {};
     QhullError(int code, const char *fmt, int d, int d2, float f) : RoadError(code, fmt, d, d2, f) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, const char *s) : RoadError(code, fmt, d, d2, f, s) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, const void *x) : RoadError(code, fmt, d, d2, f, x) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, int i) : RoadError(code, fmt, d, d2, f, i) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, long long i) : RoadError(code, fmt, d, d2, f, i) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, double e) : RoadError(code, fmt, d, d2, f, e) {};
     QhullError &operator=(const QhullError &other) { this->RoadError::operator=(other); return *this; }
     ~QhullError() throw() {}
 
 };//class QhullError
 
 
 }//namespace orgQhull
 
 #//!\name Global
 
 inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullError &e) { return os << e.what(); }
 
 #endif // QHULLERROR_H
diff --git a/src/libqhullcpp/QhullFacet.cpp b/src/libqhullcpp/QhullFacet.cpp
index ac5780d..bb4bef4 100644
--- a/src/libqhullcpp/QhullFacet.cpp
+++ b/src/libqhullcpp/QhullFacet.cpp
@@ -1,506 +1,506 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacet.cpp#13 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacet.cpp#14 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullFacet -- Qhull's facet structure, facetT, as a C++ class
 
 #include "QhullError.h"
 #include "Qhull.h"
 #include "QhullSet.h"
 #include "QhullPoint.h"
 #include "QhullPointSet.h"
 #include "QhullRidge.h"
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 #include "QhullVertex.h"
 
 #include 
 
 using std::endl;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//!\name Class objects
 facetT QhullFacet::
 s_empty_facet= {0,0,0,0,{0},
         0,0,0,0,0,
         0,0,0,0,0,
         0,0,0,0,0,
         0,0,0,0,0,
         0,0,0,0,0,
         0,0,0,0,0,
         0,0,0,0};
 
 #//!\name Constructors
 
 QhullFacet::
 QhullFacet(const Qhull &q) 
 : qh_facet(&s_empty_facet)
 , qh_qh(q.qh())
 {
 }
 
 QhullFacet::
 QhullFacet(const Qhull &q, facetT *f) 
 : qh_facet(f ? f : &s_empty_facet)
 , qh_qh(q.qh())
 {
 }
 
 #//!\name GetSet
 
 //! Return voronoi center or facet centrum.  Derived from qh_printcenter [io_r.c]
 //! printFormat=qh_PRINTtriangles if return centrum of a Delaunay facet
 //! Sets center if needed
 //! Code duplicated for PrintCenter and getCenter
 //! Returns QhullPoint() if none or qh_INFINITE
 QhullPoint QhullFacet::
 getCenter(qh_PRINT printFormat)
 {
     if(qh_qh->CENTERtype==qh_ASvoronoi){
         if(!qh_facet->normal || !qh_facet->upperdelaunay || !qh_qh->ATinfinity){
             if(!qh_facet->center){
                 QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
                     qh_facet->center= qh_facetcenter(qh_qh, qh_facet->vertices);
                 }
                 qh_qh->maybeThrowQhullMessage(QH_TRY_status);
             }
             return QhullPoint(qh_qh, qh_qh->hull_dim-1, qh_facet->center);
         }
     }else if(qh_qh->CENTERtype==qh_AScentrum){
         volatile int numCoords= qh_qh->hull_dim;
         if(printFormat==qh_PRINTtriangles && qh_qh->DELAUNAY){
             numCoords--;
         }
         if(!qh_facet->center){
             QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
                 qh_facet->center= qh_getcentrum(qh_qh, getFacetT());
             }
             qh_qh->maybeThrowQhullMessage(QH_TRY_status);
         }
         return QhullPoint(qh_qh, numCoords, qh_facet->center);
     }
     return QhullPoint(qh_qh);
  }//getCenter
 
 //! Return innerplane clearly below the vertices
 //! from io_r.c[qh_PRINTinner]
 QhullHyperplane QhullFacet::
 innerplane() const{
     realT inner;
     // Does not error
     qh_outerinner(qh_qh, const_cast(getFacetT()), NULL, &inner);
     QhullHyperplane h= hyperplane();
     h.setOffset(h.offset()-inner); //inner is negative
     return h;
 }//innerplane
 
 //! Return outerplane clearly above all points
 //! from io_r.c[qh_PRINTouter]
 QhullHyperplane QhullFacet::
 outerplane() const{
     realT outer;
     // Does not error
     qh_outerinner(qh_qh, const_cast(getFacetT()), &outer, NULL);
     QhullHyperplane h= hyperplane();
     h.setOffset(h.offset()-outer); //outer is positive
     return h;
 }//outerplane
 
 //! Set by qh_triangulate for option 'Qt'.
 //! Errors if tricoplanar and facetArea() or qh_getarea() called first.
 QhullFacet QhullFacet::
 tricoplanarOwner() const
 {
     if(qh_facet->tricoplanar){
         if(qh_facet->isarea){
             throw QhullError(10018, "Qhull error: facetArea() or qh_getarea() previously called.  triCoplanarOwner() is not available.");
         }
         return QhullFacet(qh_qh, qh_facet->f.triowner);
     }
     return QhullFacet(qh_qh); 
 }//tricoplanarOwner
 
 QhullPoint QhullFacet::
 voronoiVertex()
 {
     if(qh_qh->CENTERtype!=qh_ASvoronoi){
           throw QhullError(10052, "Error: QhullFacet.voronoiVertex() requires option 'v' (qh_ASvoronoi)");
     }
     return getCenter();
 }//voronoiVertex
 
 #//Value
 
 //! Disables tricoplanarOwner()
 double QhullFacet::
 facetArea()
 {
     if(!qh_facet->isarea){
         QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
             qh_facet->f.area= qh_facetarea(qh_qh, qh_facet);
             qh_facet->isarea= True;
         }
         qh_qh->maybeThrowQhullMessage(QH_TRY_status);
     }
     return qh_facet->f.area;
 }//facetArea
 
 #//!\name Foreach
 
 QhullPointSet QhullFacet::
 coplanarPoints() const
 {
     return QhullPointSet(qh_qh, qh_facet->coplanarset);
 }//coplanarPoints
 
 QhullFacetSet QhullFacet::
 neighborFacets() const
 {
     return QhullFacetSet(qh_qh, qh_facet->neighbors);
 }//neighborFacets
 
 QhullPointSet QhullFacet::
 outsidePoints() const
 {
     return QhullPointSet(qh_qh, qh_facet->outsideset);
 }//outsidePoints
 
 QhullRidgeSet QhullFacet::
 ridges() const
 {
     return QhullRidgeSet(qh_qh, qh_facet->ridges);
 }//ridges
 
 QhullVertexSet QhullFacet::
 vertices() const
 {
     return QhullVertexSet(qh_qh, qh_facet->vertices);
 }//vertices
 
 }//namespace orgQhull
 
 #//!\name GetSet<<
 
 using std::ostream;
 
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetSet;
 using orgQhull::QhullPoint;
 using orgQhull::QhullPointSet;
 using orgQhull::QhullRidge;
 using orgQhull::QhullRidgeSet;
 using orgQhull::QhullSetBase;
 using orgQhull::QhullVertexSet;
 
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintFacet &pr)
 {
     QhullFacet f= *pr.facet;
     if(f.getFacetT()==0){ // Special values from set iterator
         os << " NULLfacet" << endl;
         return os;
     }
     if(f.getFacetT()==qh_MERGEridge){
         os << " MERGEridge" << endl;
         return os;
     }
     if(f.getFacetT()==qh_DUPLICATEridge){
         os << " DUPLICATEridge" << endl;
         return os;
     }
     os << f.printHeader();
     if(!f.ridges().isEmpty()){
         os << f.printRidges();
     }
     return os;
 }//operator<< PrintFacet
 
 //! Print Voronoi center or facet centrum to stream.  Same as qh_printcenter [_r.]
 //! Code duplicated for PrintCenter and getCenter
 //! Sets center if needed
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintCenter &pr)
 {
     facetT *f= pr.facet->getFacetT();
     if(pr.facet->qh()->CENTERtype!=qh_ASvoronoi && pr.facet->qh()->CENTERtype!=qh_AScentrum){
         return os;
     }
     if (pr.message){
         os << pr.message;
     }
     int numCoords;
     if(pr.facet->qh()->CENTERtype==qh_ASvoronoi){
         numCoords= pr.facet->qh()->hull_dim-1;
         if(!f->normal || !f->upperdelaunay || !pr.facet->qh()->ATinfinity){
             if(!f->center){
                 f->center= qh_facetcenter(pr.facet->qh(), f->vertices);
             }
             for(int k=0; kcenter[k] << " "; // FIXUP QH11010 qh_REAL_1
             }
         }else{
             for(int k=0; kqh()->hull_dim;
         if(pr.print_format==qh_PRINTtriangles && pr.facet->qh()->DELAUNAY){
             numCoords--;
         }
         if(!f->center){
             f->center= qh_getcentrum(pr.facet->qh(), f);
         }
         for(int k=0; kcenter[k] << " "; // FIXUP QH11010 qh_REAL_1
         }
     }
     if(pr.print_format==qh_PRINTgeom && numCoords==2){
         os << " 0";
     }
     os << endl;
     return os;
 }//operator<< PrintCenter
 
 //! Print flags for facet to stream.  Space prefix.  From qh_printfacetheader [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintFlags &p)
 {
     const facetT *f= p.facet->getFacetT();
     if(p.message){
         os << p.message;
     }
 
     os << (p.facet->isTopOrient() ? " top" : " bottom");
     if(p.facet->isSimplicial()){
         os << " simplicial";
     }
     if(p.facet->isTriCoplanar()){
         os << " tricoplanar";
     }
     if(p.facet->isUpperDelaunay()){
         os << " upperDelaunay";
     }
     if(f->visible){
         os << " visible";
     }
     if(f->newfacet){
         os << " new";
     }
     if(f->tested){
         os << " tested";
     }
     if(!f->good){
         os << " notG";
     }
     if(f->seen){
         os << " seen";
     }
     if(f->coplanar){
         os << " coplanar";
     }
     if(f->mergehorizon){
         os << " mergehorizon";
     }
     if(f->keepcentrum){
         os << " keepcentrum";
     }
     if(f->dupridge){
         os << " dupridge";
     }
     if(f->mergeridge && !f->mergeridge2){
         os << " mergeridge1";
     }
     if(f->mergeridge2){
         os << " mergeridge2";
     }
     if(f->newmerge){
         os << " newmerge";
     }
     if(f->flipped){
         os << " flipped";
     }
     if(f->notfurthest){
         os << " notfurthest";
     }
     if(f->degenerate){
         os << " degenerate";
     }
     if(f->redundant){
         os << " redundant";
     }
     os << endl;
     return os;
 }//operator<< PrintFlags
 
 //! Print header for facet to stream. Space prefix.  From qh_printfacetheader [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintHeader &pr)
 {
     QhullFacet facet= *pr.facet;
     facetT *f= facet.getFacetT();
     os << "- f" << facet.id() << endl;
     os << facet.printFlags("    - flags:");
     if(f->isarea){
         os << "    - area: " << f->f.area << endl; //FIXUP QH11010 2.2g
     }else if(pr.facet->qh()->NEWfacets && f->visible && f->f.replace){
         os << "    - replacement: f" << f->f.replace->id << endl;
     }else if(f->newfacet){
         if(f->f.samecycle && f->f.samecycle != f){
             os << "    - shares same visible/horizon as f" << f->f.samecycle->id << endl;
         }
     }else if(f->tricoplanar /* !isarea */){
         if(f->f.triowner){
             os << "    - owner of normal & centrum is facet f" << f->f.triowner->id << endl;
         }
     }else if(f->f.newcycle){
         os << "    - was horizon to f" << f->f.newcycle->id << endl;
     }
     if(f->nummerge){
         os << "    - merges: " << f->nummerge << endl;
     }
     os << facet.hyperplane().print("    - normal: ", "\n    - offset: "); // FIXUP QH11010 %10.7g
     if(pr.facet->qh()->CENTERtype==qh_ASvoronoi || f->center){
         os << facet.printCenter(qh_PRINTfacets, "    - center: ");
     }
 #if qh_MAXoutside
     if(f->maxoutside > pr.facet->qh()->DISTround){
         os << "    - maxoutside: " << f->maxoutside << endl; //FIXUP QH11010 %10.7g
     }
 #endif
     QhullPointSet ps= facet.outsidePoints();
     if(!ps.isEmpty()){
         QhullPoint furthest= ps.last();
         if (ps.size() < 6) {
             os << "    - outside set(furthest p" << furthest.id() << "):" << endl;
             for(QhullPointSet::iterator i=ps.begin(); i!=ps.end(); ++i){
                 QhullPoint p= *i;
                 os << p.print("     ");
             }
         }else if(ps.size()<21){
             os << ps.print("    - outside set:");
         }else{
             os << "    - outside set:  " << ps.size() << " points.";
             os << furthest.print("  Furthest");
         }
 #if !qh_COMPUTEfurthest
         os << "    - furthest distance= " << f->furthestdist << endl; //FIXUP QH11010 %2.2g
 #endif
     }
     QhullPointSet cs= facet.coplanarPoints();
     if(!cs.isEmpty()){
         QhullPoint furthest= cs.last();
         if (cs.size() < 6) {
             os << "    - coplanar set(furthest p" << furthest.id() << "):" << endl;
             for(QhullPointSet::iterator i=cs.begin(); i!=cs.end(); ++i){
                 QhullPoint p= *i;
                 os << p.print("     ");
             }
         }else if(cs.size()<21){
             os << cs.print("    - coplanar set:");
         }else{
             os << "    - coplanar set:  " << cs.size() << " points.";
             os << furthest.print("  Furthest");
         }
         // FIXUP zinc_(Zdistio);
         double d= facet.distance(furthest);
         os << "      furthest distance= " << d << endl; //FIXUP QH11010 %2.2g
     }
     QhullVertexSet vs= facet.vertices();
     if(!vs.isEmpty()){
         os << vs.print("    - vertices:");
     }
     QhullFacetSet fs= facet.neighborFacets();
     fs.selectAll();
     if(!fs.isEmpty()){
         os << fs.printIdentifiers("    - neighboring facets:");
     }
     return os;
 }//operator<< PrintHeader
 
 
 //! Print ridges of facet to stream.  Same as qh_printfacetridges [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintRidges &pr)
 {
     const QhullFacet facet= *pr.facet;
     facetT *f= facet.getFacetT();
     QhullRidgeSet rs= facet.ridges();
     if(!rs.isEmpty()){
         if(f->visible && pr.facet->qh()->NEWfacets){
             os << "    - ridges(ids may be garbage):";
             for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
                 QhullRidge r= *i;
                 os << " r" << r.id();
             }
             os << endl;
         }else{
             os << "    - ridges:" << endl;
         }
 
         // Keep track of printed ridges
         for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
             QhullRidge r= *i;
             r.getRidgeT()->seen= false;
         }
         int ridgeCount= 0;
         if(facet.dimension()==3){
             for(QhullRidge r= rs.first(); !r.getRidgeT()->seen; r= r.nextRidge3d(facet)){
                 r.getRidgeT()->seen= true;
                 os << r.print("");
                 ++ridgeCount;
                 if(!r.hasNextRidge3d(facet)){
                     break;
                 }
             }
         }else {
             QhullFacetSet ns(facet.neighborFacets());
             for(QhullFacetSet::iterator i=ns.begin(); i!=ns.end(); ++i){
                 QhullFacet neighbor= *i;
                 QhullRidgeSet nrs(neighbor.ridges());
                 for(QhullRidgeSet::iterator j=nrs.begin(); j!=nrs.end(); ++j){
                     QhullRidge r= *j;
                     if(r.otherFacet(neighbor)==facet){
                         r.getRidgeT()->seen= true;
                         os << r.print("");
                         ridgeCount++;
                     }
                 }
             }
         }
         if(ridgeCount!=rs.count()){
             os << "     - all ridges:";
             for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
                 QhullRidge r= *i;
                 os << " r" << r.id();
             }
             os << endl;
         }
         for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
             QhullRidge r= *i;
             if(!r.getRidgeT()->seen){
                 os << r.print("");
             }
         }
     }
     return os;
 }//operator<< PrintRidges
 
 // "No conversion" error if defined inline
 ostream &
 operator<<(ostream &os, QhullFacet &f)
 {
     os << f.print();
     return os;
 }//<< QhullFacet
diff --git a/src/libqhullcpp/QhullFacet.h b/src/libqhullcpp/QhullFacet.h
index 7cd4b6c..a86fc60 100644
--- a/src/libqhullcpp/QhullFacet.h
+++ b/src/libqhullcpp/QhullFacet.h
@@ -1,151 +1,151 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacet.h#13 $$Change: 1800 $
-** $DateTime: 2014/12/17 21:46:45 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacet.h#14 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLFACET_H
 #define QHULLFACET_H
 
 #include "QhullHyperplane.h"
 #include "QhullPoint.h"
 #include "QhullSet.h"
 #include "QhullPointSet.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Used here
     class Coordinates;
     class Qhull;
     class QhullFacetSet;
     class QhullRidge;
     class QhullVertex;
     class QhullVertexSet;
 
 #//!\name Defined here
     class QhullFacet;
     typedef QhullSet  QhullRidgeSet;
 
 //! A QhullFacet is the C++ equivalent to Qhull's facetT*
 class QhullFacet {
 
 #//!\name Defined here
 public:
     typedef facetT *   base_type;  // for QhullVertexSet
 
 private:
 #//!\name Fields -- no additions (QhullFacetSet of facetT*)
     facetT *            qh_facet;  //! May be 0 (!isDefined) for corner cases (e.g., *facetSet.end()==0) and tricoplanarOwner()
     QhullQh *           qh_qh;     //! qhT
 
 #//!\name Class objects
     static facetT       s_empty_facet; // needed for shallow copy
 
 public:
 #//!\name Constructors
     explicit            QhullFacet(const Qhull &q);
                         QhullFacet(const Qhull &q, facetT *f);
     explicit            QhullFacet(QhullQh *qh) : qh_facet(&s_empty_facet), qh_qh(qh) {}
                         QhullFacet(QhullQh *qh, facetT *f) : qh_facet(f ? f : &s_empty_facet), qh_qh(qh) {}
                         // Creates an alias.  Does not copy QhullFacet.  Needed for return by value and parameter passing
                         QhullFacet(const QhullFacet &other) : qh_facet(other.qh_facet ? other.qh_facet : &s_empty_facet), qh_qh(other.qh_qh) {}
                         // Creates an alias.  Does not copy QhullFacet.  Needed for vector
     QhullFacet &        operator=(const QhullFacet &other) { qh_facet= other.qh_facet ? other.qh_facet : &s_empty_facet; qh_qh= other.qh_qh; return *this; }
                         ~QhullFacet() {}
 
 
 #//!\name GetSet
     int                 dimension() const { return qh_qh->hull_dim; }
     QhullPoint          getCenter() { return getCenter(qh_PRINTpoints); }
     QhullPoint          getCenter(qh_PRINT printFormat);
     facetT *            getBaseT() const { return getFacetT(); } //!< For QhullSet
                         // Do not define facetT().  It conflicts with return type facetT*
     facetT *            getFacetT() const { return qh_facet; }
     QhullHyperplane     hyperplane() const { return QhullHyperplane(qh_qh, dimension(), qh_facet->normal, qh_facet->offset); }
     countT              id() const { return (qh_facet ? qh_facet->id : -1); }
     QhullHyperplane     innerplane() const;
     bool                isDefined() const { return qh_facet && qh_facet != &s_empty_facet; }
     bool                isGood() const { return qh_facet && qh_facet->good; }
     bool                isSimplicial() const { return qh_facet && qh_facet->simplicial; }
     bool                isTopOrient() const { return qh_facet && qh_facet->toporient; }
     bool                isTriCoplanar() const { return qh_facet && qh_facet->tricoplanar; }
     bool                isUpperDelaunay() const { return qh_facet && qh_facet->upperdelaunay; }
     QhullFacet          next() const { return QhullFacet(qh_qh, qh_facet->next); }
     bool                operator==(const QhullFacet &other) const { return qh_facet==other.qh_facet; }
     bool                operator!=(const QhullFacet &other) const { return !operator==(other); }
     QhullHyperplane     outerplane() const;
     QhullFacet          previous() const { return QhullFacet(qh_qh, qh_facet->previous); }
     QhullQh *           qh() const { return qh_qh; }
     QhullFacet          tricoplanarOwner() const;
     QhullPoint          voronoiVertex();
 
 #//!\name value
     //! Undefined if c.size() != dimension()
     double              distance(const Coordinates &c) const { return distance(c.data()); }
     double              distance(const pointT *p) const { return distance(QhullPoint(qh_qh, const_cast(p))); }
     double              distance(const QhullPoint &p) const { return hyperplane().distance(p); }
     double              facetArea();
 
 #//!\name foreach
     // Can not inline.  Otherwise circular reference
     QhullPointSet       coplanarPoints() const;
     QhullFacetSet       neighborFacets() const;
     QhullPointSet       outsidePoints() const;
     QhullRidgeSet       ridges() const;
     QhullVertexSet      vertices() const;
 
 #//!\name IO
     struct PrintCenter{
         QhullFacet *    facet;  // non-const due to facet.center()
         const char *    message;
         qh_PRINT        print_format;
                         PrintCenter(QhullFacet &f, qh_PRINT printFormat, const char * s) : facet(&f), message(s), print_format(printFormat){}
     };//PrintCenter
     PrintCenter         printCenter(qh_PRINT printFormat, const char *message) { return PrintCenter(*this, printFormat, message); }
 
     struct PrintFacet{
         QhullFacet *    facet;  // non-const due to f->center()
         explicit        PrintFacet(QhullFacet &f) : facet(&f) {}
     };//PrintFacet
     PrintFacet          print() { return PrintFacet(*this); }
 
     struct PrintFlags{
         const QhullFacet *facet;
         const char *    message;
                         PrintFlags(const QhullFacet &f, const char *s) : facet(&f), message(s) {}
     };//PrintFlags
     PrintFlags          printFlags(const char *message) const { return PrintFlags(*this, message); }
 
     struct PrintHeader{
         QhullFacet *    facet;  // non-const due to f->center()
                         PrintHeader(QhullFacet &f) : facet(&f) {}
     };//PrintHeader
     PrintHeader         printHeader() { return PrintHeader(*this); }
 
     struct PrintRidges{
         const QhullFacet *facet;
                         PrintRidges(QhullFacet &f) : facet(&f) {}
     };//PrintRidges
     PrintRidges         printRidges() { return PrintRidges(*this); }
 
 };//class QhullFacet
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintCenter &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintFlags &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintHeader &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintRidges &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintFacet &pr);
 std::ostream &operator<<(std::ostream &os, orgQhull::QhullFacet &f); // non-const due to qh_getcenter()
 
 #endif // QHULLFACET_H
diff --git a/src/libqhullcpp/QhullFacetList.cpp b/src/libqhullcpp/QhullFacetList.cpp
index cbd3b64..1a042c5 100644
--- a/src/libqhullcpp/QhullFacetList.cpp
+++ b/src/libqhullcpp/QhullFacetList.cpp
@@ -1,172 +1,172 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacetList.cpp#7 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacetList.cpp#8 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullFacetList -- Qhull's linked facets, as a C++ class
 
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "QhullPoint.h"
 #include "QhullRidge.h"
 #include "QhullVertex.h"
 
 using std::string;
 using std::vector;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//!\name Constructors
 
 QhullFacetList::
 QhullFacetList(const Qhull &q, facetT *b, facetT *e ) 
 : QhullLinkedList(QhullFacet(q, b), QhullFacet(q, e))
 , select_all(false)
 {
 }
 
 #//!\name Conversions
 
 // See qt_qhull.cpp for QList conversions
 
 #ifndef QHULL_NO_STL
 std::vector QhullFacetList::
 toStdVector() const
 {
     QhullLinkedListIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.push_back(f);
         }
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #ifndef QHULL_NO_STL
 //! Same as PrintVertices
 std::vector QhullFacetList::
 vertices_toStdVector() const
 {
     std::vector vs;
     QhullVertexSet qvs(qh(), first().getFacetT(), 0, isSelectAll());
 
     for(QhullVertexSet::iterator i=qvs.begin(); i!=qvs.end(); ++i){
         vs.push_back(*i);
     }
     return vs;
 }//vertices_toStdVector
 #endif //QHULL_NO_STL
 
 #//!\name GetSet
 
 bool QhullFacetList::
 contains(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullLinkedList::contains(facet);
     }
     for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             return true;
         }
     }
     return false;
 }//contains
 
 int QhullFacetList::
 count() const
 {
     if(isSelectAll()){
         return QhullLinkedList::count();
     }
     int counter= 0;
     for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
         if((*i).isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 int QhullFacetList::
 count(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullLinkedList::count(facet);
     }
     int counter= 0;
     for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetList;
 using orgQhull::QhullVertex;
 using orgQhull::QhullVertexSet;
 
 ostream &
 operator<<(ostream &os, const QhullFacetList::PrintFacetList &pr)
 {
     QhullFacetList fs= *pr.facet_list;
     os << "Vertices for " << fs.count() << " facets" << endl;
     os << fs.printVertices();
     os << fs.printFacets();
     return os;
 }//operator<<
 
 //! Print facet list to stream.  From qh_printafacet [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullFacetList::PrintFacets &pr)
 {
     for(QhullFacetList::const_iterator i= pr.facet_list->begin(); i != pr.facet_list->end(); ++i){
         QhullFacet f= *i;
         if(pr.facet_list->isSelectAll() || f.isGood()){
             os << f.print();
         }
     }
     return os;
 }//printFacets
 
 //! Print vertices of good faces in facet list to stream.  From qh_printvertexlist [io_r.c]
 //! Same as vertices_toStdVector
 ostream &
 operator<<(ostream &os, const QhullFacetList::PrintVertices &pr)
 {
     QhullVertexSet vs(pr.facet_list->qh(), pr.facet_list->first().getFacetT(), NULL, pr.facet_list->isSelectAll());
     for(QhullVertexSet::iterator i=vs.begin(); i!=vs.end(); ++i){
         QhullVertex v= *i;
         os << v.print("");
     }
     return os;
 }//printVertices
 
 std::ostream &
 operator<<(ostream &os, const QhullFacetList &fs)
 {
     os << fs.printFacets();
     return os;
 }//QhullFacetList
 
diff --git a/src/libqhullcpp/QhullFacetList.h b/src/libqhullcpp/QhullFacetList.h
index 4b6bb64..20348f5 100644
--- a/src/libqhullcpp/QhullFacetList.h
+++ b/src/libqhullcpp/QhullFacetList.h
@@ -1,104 +1,104 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacetList.h#9 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacetList.h#10 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLFACETLIST_H
 #define QHULLFACETLIST_H
 
 #include "QhullLinkedList.h"
 #include "QhullFacet.h"
 
 #include 
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Used here
     class Qhull;
     class QhullFacet;
     class QhullQh;
 
 #//!\name Defined here
     //! QhullFacetList -- List of Qhull facets, as a C++ class.  See QhullFacetSet.h
     class QhullFacetList;
     //! QhullFacetListIterator -- if(f.isGood()){ ... }
     typedef QhullLinkedListIterator QhullFacetListIterator;
 
 class QhullFacetList : public QhullLinkedList {
 
 #//!\name  Fields
 private:
     bool                select_all;   //! True if include bad facets.  Default is false.
 
 #//!\name Constructors
 public:
                         QhullFacetList(const Qhull &q, facetT *b, facetT *e);
                         QhullFacetList(QhullQh *qh, facetT *b, facetT *e);
                         QhullFacetList(QhullFacet b, QhullFacet e) : QhullLinkedList(b, e), select_all(false) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullFacetList(const QhullFacetList &other) : QhullLinkedList(*other.begin(), *other.end()), select_all(other.select_all) {}
     QhullFacetList &    operator=(const QhullFacetList &other) { QhullLinkedList::operator =(other); select_all= other.select_all; }
                         ~QhullFacetList() {}
 
 private:                //!Disable default constructor.  See QhullLinkedList
                         QhullFacetList();
 public:
 
 #//!\name Conversion
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
     std::vector vertices_toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList   toQList() const;
     QList  vertices_toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
                         //! Filtered by facet.isGood().  May be 0 when !isEmpty().
     countT              count() const;
     bool                contains(const QhullFacet &f) const;
     countT              count(const QhullFacet &f) const;
     bool                isSelectAll() const { return select_all; }
     QhullQh *           qh() const { return first().qh(); }
     void                selectAll() { select_all= true; }
     void                selectGood() { select_all= false; }
                         //!< operator==() does not depend on isGood()
 
 #//!\name IO
     struct PrintFacetList{
         const QhullFacetList *facet_list;
                         PrintFacetList(const QhullFacetList &fl) : facet_list(&fl) {}
     };//PrintFacetList
     PrintFacetList      print() const  { return PrintFacetList(*this); }
 
     struct PrintFacets{
         const QhullFacetList *facet_list;
                         PrintFacets(const QhullFacetList &fl) : facet_list(&fl) {}
     };//PrintFacets
     PrintFacets         printFacets() const { return PrintFacets(*this); }
 
     struct PrintVertices{
         const QhullFacetList *facet_list;
                         PrintVertices(const QhullFacetList &fl) : facet_list(&fl) {}
     };//PrintVertices
     PrintVertices       printVertices() const { return PrintVertices(*this); }
 };//class QhullFacetList
 
 }//namespace orgQhull
 
 #//!\name == Global namespace =========================================
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintFacetList &p);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintFacets &p);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintVertices &p);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList &fs);
 
 #endif // QHULLFACETLIST_H
diff --git a/src/libqhullcpp/QhullFacetSet.cpp b/src/libqhullcpp/QhullFacetSet.cpp
index 411b730..c231527 100644
--- a/src/libqhullcpp/QhullFacetSet.cpp
+++ b/src/libqhullcpp/QhullFacetSet.cpp
@@ -1,147 +1,147 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacetSet.cpp#10 $$Change: 1800 $
-** $DateTime: 2014/12/17 21:46:45 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullFacetSet.cpp#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullFacetSet -- Qhull's linked facets, as a C++ class
 
 #include "QhullFacetSet.h"
 
 #include "QhullFacet.h"   // Before QhullFacetSet for base_type
 #include "QhullPoint.h"
 #include "QhullRidge.h"
 #include "QhullVertex.h"
 
 #ifndef QHULL_NO_STL
 using std::vector;
 #endif
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//!\name Conversions
 
 // See qt-qhull.cpp for QList conversions
 
 #ifndef QHULL_NO_STL
 std::vector QhullFacetSet::
 toStdVector() const
 {
     QhullSetIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.push_back(f);
         }
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//!\name GetSet
 
 bool QhullFacetSet::
 contains(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullSet::contains(facet);
     }
     for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             return true;
         }
     }
     return false;
 }//contains
 
 int QhullFacetSet::
 count() const
 {
     if(isSelectAll()){
         return QhullSet::count();
     }
     int counter= 0;
     for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f.isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 int QhullFacetSet::
 count(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullSet::count(facet);
     }
     int counter= 0;
     for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetSet;
 
 ostream &
 operator<<(ostream &os, const QhullFacetSet &fs)
 {
     os << fs.print("");
     return os;
 }//<begin(); i!=p.facet_set->end(); ++i){
         const QhullFacet f= *i;
         if(f.getFacetT()==qh_MERGEridge){
             os << " MERGE";
         }else if(f.getFacetT()==qh_DUPLICATEridge){
             os << " DUP";
         }else if(p.facet_set->isSelectAll() || f.isGood()){
             os << " f" << f.id();
         }
     }
     os << endl;
     return os;
 }//<
 
 namespace orgQhull {
 
 #//!\name Used here
     class Qhull;
 
 #//!\name Defined here
     //! QhullFacetSet -- a set of Qhull facets, as a C++ class.  See QhullFacetList.h
     class QhullFacetSet;
     typedef QhullSetIterator QhullFacetSetIterator;
 
 class QhullFacetSet : public QhullSet {
 
 #//!\name Defined here
 public:
     typedef facetT *   base_type;  // for QhullVertexSet
 
 private:
 #//!\name Fields
     bool                select_all;   //! True if include bad facets.  Default is false.
 
 public:
 #//!\name Constructor
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                         QhullFacetSet(const Qhull &q, setT *s) : QhullSet(q, s), select_all(false) {}
                         QhullFacetSet(QhullQh *qh, setT *s) : QhullSet(qh, s), select_all(false) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullFacetSet(const QhullFacetSet &other) : QhullSet(other), select_all(other.select_all) {}
     QhullFacetSet &     operator=(const QhullFacetSet &other) { QhullSet::operator=(other); select_all= other.select_all; }
 
 private:
                         //!Disable default constructor.  See QhullSetBase
                         QhullFacetSet();
 public:
 
 #//!\name Conversion
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList   toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
                         //! Filtered by facet.isGood().  May be 0 when !isEmpty().
     countT              count() const;
     bool                contains(const QhullFacet &f) const;
     countT              count(const QhullFacet &f) const;
     bool                isSelectAll() const { return select_all; }
                         //! operator==() does not depend on isGood()
     void                selectAll() { select_all= true; }
     void                selectGood() { select_all= false; }
 
 #//!\name IO
     // Not same as QhullFacetList#IO.  A QhullFacetSet is a component of a QhullFacetList.
 
     struct PrintFacetSet{
         const QhullFacetSet *facet_set;
         const char *    print_message;
                         PrintFacetSet(const char *message, const QhullFacetSet *s) : facet_set(s), print_message(message) {}
     };//PrintFacetSet
     const PrintFacetSet print(const char *message) const { return PrintFacetSet(message, this); }
 
     struct PrintIdentifiers{
         const QhullFacetSet *facet_set;
         const char *    print_message;
                         PrintIdentifiers(const char *message, const QhullFacetSet *s) : facet_set(s), print_message(message) {}
     };//PrintIdentifiers
     PrintIdentifiers    printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }
 
 };//class QhullFacetSet
 
 }//namespace orgQhull
 
 #//!\name == Global namespace =========================================
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet &fs);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet::PrintFacetSet &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet::PrintIdentifiers &p);
 
 #endif // QHULLFACETSET_H
diff --git a/src/libqhullcpp/QhullHyperplane.cpp b/src/libqhullcpp/QhullHyperplane.cpp
index 0a6f51f..480a757 100644
--- a/src/libqhullcpp/QhullHyperplane.cpp
+++ b/src/libqhullcpp/QhullHyperplane.cpp
@@ -1,185 +1,185 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullHyperplane.cpp#10 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullHyperplane.cpp#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullHyperplane.h"
 
 #include "Qhull.h"
 #include "QhullPoint.h"
 
 #include 
 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Constructors
 
 QhullHyperplane::
 QhullHyperplane(const Qhull &q) 
 : hyperplane_coordinates(0)
 , hyperplane_dimension(0)
 , hyperplane_offset(0.0)
 , qh_qh(q.qh())
 {
 }
 
 QhullHyperplane::
 QhullHyperplane(const Qhull &q, int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) 
 : hyperplane_coordinates(c)
 , hyperplane_dimension(hyperplaneDimension)
 , hyperplane_offset(hyperplaneOffset)
 , qh_qh(q.qh())
 {
 }
 
 #//!\name Conversions
 
 // See qt-qhull.cpp for QList conversions
 
 #ifndef QHULL_NO_STL
 std::vector QhullHyperplane::
 toStdVector() const
 {
     QhullHyperplaneIterator i(*this);
     std::vector fs;
     while(i.hasNext()){
         fs.push_back(i.next());
     }
     fs.push_back(hyperplane_offset);
     return fs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//!\name GetSet
 
 bool QhullHyperplane::
 operator==(const QhullHyperplane &other) const
 {
     if(hyperplane_dimension!=other.hyperplane_dimension){
         return false;
     }
     double d= fabs(hyperplane_offset-other.hyperplane_offset);
     if(d>qh_qh->distanceEpsilon()){
         return false;
     }
     const coordT *c= hyperplane_coordinates;
     const coordT *c2= other.hyperplane_coordinates;
     if(c==c2){
         return true;
     }
     double dist2= 0.0;
     for(int k= hyperplane_dimension; k--; ){
         double diff= *c++ - *c2++;
         dist2 += diff*diff;
     }
     if(dist2 > qh_qh->angleEpsilon()){
         return false;
     }
     return true;
 }//operator==
 
 #//!\name Methods
 
 //! Return distance from point to hyperplane.
 //!   If greater than zero, the point is above the facet (i.e., outside).
 // qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies
 //    Does not support RANDOMdist or logging
 double QhullHyperplane::
 distance(const QhullPoint &p) const
 {
     const coordT *point= p.coordinates();
     int dim= p.dimension();
     QHULL_ASSERT(dim==dimension());
     const coordT *normal= coordinates();
     double dist;
 
     switch (dim){
   case 2:
       dist= offset() + point[0] * normal[0] + point[1] * normal[1];
       break;
   case 3:
       dist= offset() + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
       break;
   case 4:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
       break;
   case 5:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
       break;
   case 6:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
       break;
   case 7:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
       break;
   case 8:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
       break;
   default:
       dist= offset();
       for (int k=dim; k--; )
           dist += *point++ * *normal++;
       break;
     }
     return dist;
 }//distance
 
 double QhullHyperplane::
 norm() const {
     double d= 0.0;
     const coordT *c= coordinates();
     for (int k=dimension(); k--; ){
         d += *c * *c;
         ++c;
     }
     return sqrt(d);
 }//norm
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::ostream;
 using orgQhull::QhullHyperplane;
 
 #//!\name GetSet<<
 
 ostream &
 operator<<(ostream &os, const QhullHyperplane &p)
 {
     os << p.print();
     return os;
 }
 
 ostream &
 operator<<(ostream &os, const QhullHyperplane::PrintHyperplane &pr)
 {
     if(pr.print_message){
         os << pr.print_message;
     }
     QhullHyperplane p= *pr.hyperplane;
     const realT *c= p.coordinates();
     for(int k=p.dimension(); k--; ){
         realT r= *c++;
         if(pr.print_message){
             os << " " << r; // FIXUP QH11010 %8.4g
         }else{
             os << " " << r; // FIXUP QH11010 qh_REAL_1
         }
     }
     if(pr.hyperplane_offset_message){
         os << pr.hyperplane_offset_message << " " << p.offset();
     }else{
         os << " " << p.offset();
     }
     os << std::endl;
     return os;
 }//PrintHyperplane
 
diff --git a/src/libqhullcpp/QhullHyperplane.h b/src/libqhullcpp/QhullHyperplane.h
index eaad842..93abf3c 100644
--- a/src/libqhullcpp/QhullHyperplane.h
+++ b/src/libqhullcpp/QhullHyperplane.h
@@ -1,123 +1,123 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullHyperplane.h#11 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullHyperplane.h#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHHYPERPLANE_H
 #define QHHYPERPLANE_H
 
 #include "QhullError.h"
 #include "QhullIterator.h"
 #include "QhullQh.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Used here
     class Qhull;
     class QhullPoint;
 
 #//!\name Defined here
     //! QhullHyperplane as an offset, dimension, and pointer to coordinates
     class QhullHyperplane;
     //! Java-style iterator for QhullHyperplane coordinates
     class QhullHyperplaneIterator;
 
 class QhullHyperplane { // Similar to QhullPoint
 public:
 #//!\name Subtypes
     typedef const coordT *                  iterator;
     typedef const coordT *                  const_iterator;
     typedef QhullHyperplane::iterator       Iterator;
     typedef QhullHyperplane::const_iterator ConstIterator;
 
 private:
 #//!\name Fields
     coordT *            hyperplane_coordinates;  // Keep pointers aligned
     int                 hyperplane_dimension;
     coordT              hyperplane_offset;
     QhullQh *           qh_qh;
 
 #//!\name Construct
 public:
                         QhullHyperplane(const Qhull &q);
                         QhullHyperplane(const Qhull &q, int hyperplaneDimension, coordT *c, coordT hyperplaneOffset);
                         QhullHyperplane(QhullQh *qh) : hyperplane_coordinates(0), hyperplane_dimension(0), hyperplane_offset(0.0), qh_qh(qh) {}
                         QhullHyperplane(QhullQh *qh, int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) : hyperplane_coordinates(c), hyperplane_dimension(hyperplaneDimension), hyperplane_offset(hyperplaneOffset), qh_qh(qh) {}
                         // Creates an alias.  Does not copy the hyperplane's coordinates.  Needed for return by value and parameter passing.
                         QhullHyperplane(const QhullHyperplane &other)  : hyperplane_coordinates(other.hyperplane_coordinates), hyperplane_dimension(other.hyperplane_dimension), hyperplane_offset(other.hyperplane_offset), qh_qh(other.qh_qh) {}
                         // Creates an alias.  Does not copy the hyperplane's coordinates.  Needed for vector
     QhullHyperplane &   operator=(const QhullHyperplane &other) { hyperplane_coordinates= other.hyperplane_coordinates; hyperplane_dimension= other.hyperplane_dimension; hyperplane_offset= other.hyperplane_offset; qh_qh= other.qh_qh; return *this; }
                         ~QhullHyperplane() {}
 
 #//!\name Conversions --
 //! Includes offset at end
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList       toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
 public:
     const coordT *      coordinates() const { return hyperplane_coordinates; }
     coordT *            coordinates() { return hyperplane_coordinates; }
     void                defineAs(int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) { QHULL_ASSERT(hyperplaneDimension>=0); hyperplane_coordinates= c; hyperplane_dimension= hyperplaneDimension; hyperplane_offset= hyperplaneOffset; }
     //! Creates an alias to other using the same qh_qh
     void                defineAs(QhullHyperplane &other) { hyperplane_coordinates= other.coordinates(); hyperplane_dimension= other.dimension();  hyperplane_offset= other.offset(); }
     int                 dimension() const { return hyperplane_dimension; }
     bool                isDefined() const { return hyperplane_coordinates!=0 && hyperplane_dimension>0; }
     coordT              offset() const { return hyperplane_offset; }
     bool                operator==(const QhullHyperplane &other) const;
     bool                operator!=(const QhullHyperplane &other) const { return !operator==(other); }
     const coordT &      operator[](int idx) const { QHULL_ASSERT(idx>=0 && idx=0 && idx
 #include 
 #include 
 //! Avoid dependence on 
 namespace std { struct bidirectional_iterator_tag; struct random_access_iterator_tag; }
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! QHULL_DECLARE_SEQUENTIAL_ITERATOR(C) -- Declare a Java-style iterator
     //! QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C) -- Declare a mutable Java-style iterator
     //! QHULL_DECLARE_SET_ITERATOR(C) -- Declare a set iterator
     //! QHULL_DECLARE_MUTABLE_SET_ITERATOR(C) -- Declare a mutable set iterator
     //! Derived from Qt/core/tools/qiterator.h and qset_r.h/FOREACHsetelement_()
 
 // Changed c to C* as in Mutable...  Assumes c does not go away.
 #define QHULL_DECLARE_SEQUENTIAL_ITERATOR(C, T) \
     \
     class C##Iterator \
     { \
         typedef C::const_iterator const_iterator; \
         const C *c; \
         const_iterator i; \
         public: \
         inline C##Iterator(const C &container) \
         : c(&container), i(c->constBegin()) {} \
         inline C##Iterator &operator=(const C &container) \
         { c = &container; i = c->constBegin(); return *this; } \
         inline void toFront() { i = c->constBegin(); } \
         inline void toBack() { i = c->constEnd(); } \
         inline bool hasNext() const { return i != c->constEnd(); } \
         inline const T &next() { return *i++; } \
         inline const T &peekNext() const { return *i; } \
         inline bool hasPrevious() const { return i != c->constBegin(); } \
         inline const T &previous() { return *--i; } \
         inline const T &peekPrevious() const { const_iterator p = i; return *--p; } \
         inline bool findNext(const T &t) \
         { while (i != c->constEnd()) if (*i++ == t) return true; return false; } \
         inline bool findPrevious(const T &t) \
         { while (i != c->constBegin()) if (*(--i) == t) return true; \
         return false;  } \
     };//C##Iterator
 
 // Remove setShareable() from Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR
 // Uses QHULL_ASSERT (assert.h)
 // Duplicated in MutablePointIterator without insert or remove
 #define QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C, T) \
     class Mutable##C##Iterator \
     { \
         typedef C::iterator iterator; \
         typedef C::const_iterator const_iterator; \
         C *c; \
         iterator i, n; \
         inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
         public: \
         inline Mutable##C##Iterator(C &container) \
         : c(&container) \
         { i = c->begin(); n = c->end(); } \
         inline ~Mutable##C##Iterator() \
         {} \
         inline Mutable##C##Iterator &operator=(C &container) \
         { c = &container; \
         i = c->begin(); n = c->end(); return *this; } \
         inline void toFront() { i = c->begin(); n = c->end(); } \
         inline void toBack() { i = c->end(); n = i; } \
         inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
         inline T &next() { n = i++; return *n; } \
         inline T &peekNext() const { return *i; } \
         inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
         inline T &previous() { n = --i; return *n; } \
         inline T &peekPrevious() const { iterator p = i; return *--p; } \
         inline void remove() \
         { if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } } \
         inline void setValue(const T &t) const { if (c->constEnd() != const_iterator(n)) *n = t; } \
         inline T &value() { QHULL_ASSERT(item_exists()); return *n; } \
         inline const T &value() const { QHULL_ASSERT(item_exists()); return *n; } \
         inline void insert(const T &t) { n = i = c->insert(i, t); ++i; } \
         inline bool findNext(const T &t) \
         { while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; } \
         inline bool findPrevious(const T &t) \
         { while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true; \
         n = c->end(); return false;  } \
     };//Mutable##C##Iterator
 
 #define QHULL_DECLARE_SET_ITERATOR(C) \
 \
     template  \
     class Qhull##C##Iterator \
     { \
         typedef typename Qhull##C::const_iterator const_iterator; \
         Qhull##C c; \
         const_iterator i; \
     public: \
         inline Qhull##C##Iterator(const Qhull##C &container) \
         : c(container), i(c.constBegin()) {} \
         inline Qhull##C##Iterator &operator=(const Qhull##C &container) \
         { c = container; i = c.constBegin(); return *this; } \
         inline void toFront() { i = c.constBegin(); } \
         inline void toBack() { i = c.constEnd(); } \
         inline bool hasNext() const { return i != c.constEnd(); } \
         inline const T &next() { return *i++; } \
         inline const T &peekNext() const { return *i; } \
         inline bool hasPrevious() const { return i != c.constBegin(); } \
         inline const T &previous() { return *--i; } \
         inline const T &peekPrevious() const { const_iterator p = i; return *--p; } \
         inline bool findNext(const T &t) \
         { while (i != c.constEnd()) if (*i++ == t) return true; return false; } \
         inline bool findPrevious(const T &t) \
         { while (i != c.constBegin()) if (*(--i) == t) return true; \
         return false;  } \
     };//Qhull##C##Iterator
 
 #define QHULL_DECLARE_MUTABLE_SET_ITERATOR(C) \
 \
 template  \
 class QhullMutable##C##Iterator \
 { \
     typedef typename Qhull##C::iterator iterator; \
     typedef typename Qhull##C::const_iterator const_iterator; \
     Qhull##C *c; \
     iterator i, n; \
     inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
 public: \
     inline Mutable##C##Iterator(Qhull##C &container) \
         : c(&container) \
     { c->setSharable(false); i = c->begin(); n = c->end(); } \
     inline ~Mutable##C##Iterator() \
     { c->setSharable(true); } \
     inline Mutable##C##Iterator &operator=(Qhull##C &container) \
     { c->setSharable(true); c = &container; c->setSharable(false); \
       i = c->begin(); n = c->end(); return *this; } \
     inline void toFront() { i = c->begin(); n = c->end(); } \
     inline void toBack() { i = c->end(); n = i; } \
     inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
     inline T &next() { n = i++; return *n; } \
     inline T &peekNext() const { return *i; } \
     inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
     inline T &previous() { n = --i; return *n; } \
     inline T &peekPrevious() const { iterator p = i; return *--p; } \
     inline void remove() \
     { if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } } \
     inline void setValue(const T &t) const { if (c->constEnd() != const_iterator(n)) *n = t; } \
     inline T &value() { Q_ASSERT(item_exists()); return *n; } \
     inline const T &value() const { Q_ASSERT(item_exists()); return *n; } \
     inline void insert(const T &t) { n = i = c->insert(i, t); ++i; } \
     inline bool findNext(const T &t) \
     { while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; } \
     inline bool findPrevious(const T &t) \
     { while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true; \
       n = c->end(); return false;  } \
 };//QhullMutable##C##Iterator
 
 }//namespace orgQhull
 
 #endif // QHULLITERATOR_H
 
diff --git a/src/libqhullcpp/QhullLinkedList.h b/src/libqhullcpp/QhullLinkedList.h
index 74b0000..90877d5 100644
--- a/src/libqhullcpp/QhullLinkedList.h
+++ b/src/libqhullcpp/QhullLinkedList.h
@@ -1,380 +1,380 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullLinkedList.h#9 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullLinkedList.h#10 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLLINKEDLIST_H
 #define QHULLLINKEDLIST_H
 
 namespace std { struct bidirectional_iterator_tag; struct random_access_iterator_tag; }
 
 #include "QhullError.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #ifdef QHULL_USES_QT
 #include 
 #endif
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! QhullLinkedList -- A linked list modeled on QLinkedList.
     //!   T is an opaque type with T(B *b), b=t.getBaseT(), t=t.next(), and t=t.prev().  The end node is a sentinel.
     //!   libqhull owns the contents.
     //!   QhullLinkedList does not define erase(), clear(), removeFirst(), removeLast(), pop_back(), pop_front(), fromStdList()
     //!   Derived from Qt/core/tools/qlinkedlist.h and libqhull_r.h/FORALLfacets_()
     //! QhullLinkedList::const_iterator -- STL-style iterator
     //! QhullLinkedList::iterator -- STL-style iterator
     //! QhullLinkedListIterator -- Java-style iterator
     //!   Derived from Qt/core/tools/qiterator.h
     //!   Works with Qt's foreach keyword [Qt/src/corelib/global/qglobal.h]
 
 template 
 class QhullLinkedList
 {
 #//!\name Defined here
 public:
     class const_iterator;
     class iterator;
     typedef const_iterator  ConstIterator;
     typedef iterator    Iterator;
     typedef ptrdiff_t   difference_type;
     typedef countT      size_type;
     typedef T           value_type;
     typedef const value_type *const_pointer;
     typedef const value_type &const_reference;
     typedef value_type *pointer;
     typedef value_type &reference;
 
 #//!\name Fields
 private:
     T                   begin_node;
     T                   end_node;     //! Sentinel node at end of list
 
 #//!\name Constructors
 public:
                         QhullLinkedList(T b, T e) : begin_node(b), end_node(e) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullLinkedList(const QhullLinkedList &other) : begin_node(other.begin_node), end_node(other.end_node) {}
                         QhullLinkedList & operator=(const QhullLinkedList &other) { begin_node= other.begin_node; end_node= other.end_node; }
                         ~QhullLinkedList() {}
 
 private:
                         //!disabled since a sentinel must be allocated as the private type
                         QhullLinkedList() {}
                         //!disabled since qs= qs2 is ambiguous (pointer vs. contents)
 public:
 
 #//!\name Conversions
 #ifndef QHULL_NO_STL
     std::vector      toStdVector() const;
 #endif
 #ifdef QHULL_USES_QT
     QList            toQList() const;
 #endif
 
 #//!\name GetSet
     countT              count() const;
                         //count(t) under #//!\name Search
     bool                isEmpty() const { return (begin_node==end_node); }
     bool                operator==(const QhullLinkedList &o) const;
     bool                operator!=(const QhullLinkedList &o) const { return !operator==(o); }
     size_t              size() const { return count(); }
 
 #//!\name Element access
     //! Return by value which contains a pointer (e.g., typedef vertexT * QhullVertex).  A reference does not make sense.
     T                   back() const { return last(); }
     T                   first() const { QHULL_ASSERT(!isEmpty()); return *begin(); }
     T                   front() const { return first(); }
     T                   last() const { QHULL_ASSERT(!isEmpty()); return *--end(); }
 
 #//!\name Modify -- Allocation of opaque types not implemented.
 
 #//!\name Search
     bool                contains(const T &t) const;
     countT              count(const T &t) const;
 
 #//!\name Iterator
     iterator            begin() { return begin_node; }
     const_iterator      begin() const { return begin_node; }
     const_iterator      constBegin() const { return begin_node; }
     const_iterator      constEnd() const { return end_node; }
     iterator            end() { return end_node; }
     const_iterator      end() const { return end_node; }
 
     class iterator {
 
     private:
         T               i;
         friend class const_iterator;
 
     public:
         typedef std::bidirectional_iterator_tag  iterator_category;
         typedef T           value_type;
         typedef value_type *pointer;
         typedef value_type &reference;
         typedef ptrdiff_t   difference_type;
 
                         iterator() : i() {}
                         iterator(T t) : i(t) {}
                         iterator(const iterator &o) : i(o.i) {}
         iterator &      operator=(const iterator &o) { i= o.i; return *this; }
 
         T               operator*() const { return i; }
         T               operator->() const { return i; }
         bool            operator==(const iterator &o) const { return i == o.i; }
         bool            operator!=(const iterator &o) const { return !operator==(o); }
         bool            operator==(const const_iterator &o) const { return i==reinterpret_cast(o).i; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
         iterator &      operator++() { i= i.next(); return *this; }
         iterator        operator++(int) { iterator o= i; i= i.next(); return o; }
         iterator &      operator--() { i= i.previous(); return *this; }
         iterator        operator--(int) { iterator o= i; i= i.previous(); return o; }
         iterator        operator+(int j) const;
         iterator        operator-(int j) const { return operator+(-j); }
         iterator &      operator+=(int j) { return *this= *this + j; }
         iterator &      operator-=(int j) { return *this= *this - j; }
     };//QhullLinkedList::iterator
 
     class const_iterator {
 
     private:
         T               i;
 
     public:
         typedef std::bidirectional_iterator_tag  iterator_category;
         typedef T                 value_type;
         typedef const value_type *pointer;
         typedef const value_type &reference;
         typedef ptrdiff_t         difference_type;
 
                         const_iterator() : i() {}
                         const_iterator(T t) : i(t) {}
                         const_iterator(const const_iterator &o) : i(o.i) {}
                         const_iterator(iterator o) : i(o.i) {}
         const_iterator &operator=(const const_iterator &o) { i= o.i; return *this; }
 
         T               operator*() const { return i; }
         T               operator->() const { return i; }
         bool            operator==(const const_iterator &o) const { return i == o.i; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
                         // No comparisons or iterator diff
         const_iterator &operator++() { i= i.next(); return *this; }
         const_iterator  operator++(int) { const_iterator o= i; i= i.next(); return o; }
         const_iterator &operator--() { i= i.previous(); return *this; }
         const_iterator  operator--(int) { const_iterator o= i; i= i.previous(); return o; }
         const_iterator  operator+(int j) const;
         const_iterator  operator-(int j) const { return operator+(-j); }
         const_iterator &operator+=(int j) { return *this= *this + j; }
         const_iterator &operator-=(int j) { return *this= *this - j; }
     };//QhullLinkedList::const_iterator
 
 };//QhullLinkedList
 
 template 
 class QhullLinkedListIterator // FIXUP QH11016 define QhullMutableLinkedListIterator
 {
     typedef typename QhullLinkedList::const_iterator const_iterator;
     const QhullLinkedList *c;
     const_iterator      i;
 
 public:
                         QhullLinkedListIterator(const QhullLinkedList &container) : c(&container), i(c->constBegin()) {}
                         QhullLinkedListIterator &operator=(const QhullLinkedList &container) { c= &container; i= c->constBegin(); return *this; }
     bool                findNext(const T &t);
     bool                findPrevious(const T &t);
     bool                hasNext() const { return i != c->constEnd(); }
     bool                hasPrevious() const { return i != c->constBegin(); }
     T                   next() { return *i++; }
     T                   peekNext() const { return *i; }
     T                   peekPrevious() const { const_iterator p= i; return *--p; }
     T                   previous() { return *--i; }
     void                toFront() { i= c->constBegin(); }
     void                toBack() { i= c->constEnd(); }
 };//QhullLinkedListIterator
 
 #//!\name == Definitions =========================================
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
 template 
 std::vector QhullLinkedList::
 toStdVector() const
 {
     std::vector tmp;
     std::copy(constBegin(), constEnd(), std::back_inserter(tmp));
     return tmp;
 }//toStdVector
 #endif
 
 #ifdef QHULL_USES_QT
 template 
 QList  QhullLinkedList::
 toQList() const
 {
     QhullLinkedListIterator i(*this);
     QList ls;
     while(i.hasNext()){
         ls.append(i.next());
     }
     return ls;
 }//toQList
 #endif
 
 #//!\name GetSet
 
 template 
 countT QhullLinkedList::
 count() const
 {
     const_iterator i= begin_node;
     countT c= 0;
     while(i != end_node){
         c++;
         i++;
     }
     return c;
 }//count
 
 #//!\name Search
 
 template 
 bool QhullLinkedList::
 contains(const T &t) const
 {
     const_iterator i= begin_node;
     while(i != end_node){
         if(i==t){
             return true;
         }
         i++;
     }
     return false;
 }//contains
 
 template 
 countT QhullLinkedList::
 count(const T &t) const
 {
     const_iterator i= begin_node;
     countT c= 0;
     while(i != end_node){
         if(i==t){
             c++;
         }
         i++;
     }
     return c;
 }//count
 
 template 
 bool QhullLinkedList::
 operator==(const QhullLinkedList &l) const
 {
     if(begin_node==l.begin_node){
         return (end_node==l.end_node);
     }
     T i= begin_node;
     T il= l.begin_node;
     while(i != end_node){
         if(i != il){
             return false;
         }
         i= static_cast(i.next());
         il= static_cast(il.next());
     }
     if(il != l.end_node){
         return false;
     }
     return true;
 }//operator==
 
 #//!\name Iterator
 
 template 
 typename QhullLinkedList::iterator  QhullLinkedList::iterator::
 operator+(int j) const
 {
     T n= i;
     if(j>0){
         while(j--){
             n= n.next();
         }
     }else{
         while(j++){
             n= n.previous();
         }
     }
     return iterator(n);
 }//operator+
 
 template 
 typename QhullLinkedList::const_iterator  QhullLinkedList::const_iterator::
 operator+(int j) const
 {
     T n= i;
     if(j>0){
         while(j--){
             n= n.next();
         }
     }else{
         while(j++){
             n= n.previous();
         }
     }
     return const_iterator(n);
 }//operator+
 
 #//!\name QhullLinkedListIterator
 
 template 
 bool QhullLinkedListIterator::
 findNext(const T &t)
 {
     while(i != c->constEnd()){
         if (*i++ == t){
             return true;
         }
     }
     return false;
 }//findNext
 
 template 
 bool QhullLinkedListIterator::
 findPrevious(const T &t)
 {
     while(i!=c->constBegin()){
         if(*(--i)==t){
             return true;
         }
     }
     return false;
 }//findNext
 
 }//namespace orgQhull
 
 #//!\name Global
 
 template 
 std::ostream &
 operator<<(std::ostream &os, const orgQhull::QhullLinkedList &qs)
 {
     typename orgQhull::QhullLinkedList::const_iterator i;
     for(i= qs.begin(); i != qs.end(); ++i){
         os << *i;
     }
     return os;
 }//operator<<
 
 #endif // QHULLLINKEDLIST_H
 
diff --git a/src/libqhullcpp/QhullPoint.cpp b/src/libqhullcpp/QhullPoint.cpp
index 2378ad7..1cc0a63 100644
--- a/src/libqhullcpp/QhullPoint.cpp
+++ b/src/libqhullcpp/QhullPoint.cpp
@@ -1,189 +1,189 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullPoint.cpp#12 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullPoint.cpp#13 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullPoint.h"
 #include "QhullError.h"
 #include "Qhull.h"
 
 #include 
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Constructors
 
 
 QhullPoint::
 QhullPoint(const Qhull &q) 
 : point_coordinates(0)
 , qh_qh(q.qh())
 , point_dimension(q.hullDimension())
 {
 }//QhullPoint
 
 QhullPoint::
 QhullPoint(const Qhull &q, coordT *c) 
 : point_coordinates(c)
 , qh_qh(q.qh())
 , point_dimension(q.hullDimension())
 {
 }//QhullPoint dim, coordT
 
 QhullPoint::
 QhullPoint(const Qhull &q, int pointDimension, coordT *c) 
 : point_coordinates(c)
 , qh_qh(q.qh())
 , point_dimension(pointDimension)
 {
 }//QhullPoint dim, coordT
 
 QhullPoint::
 QhullPoint(const Qhull &q, Coordinates &c) 
 : point_coordinates(c.data())
 , qh_qh(q.qh())
 , point_dimension(c.count())
 {
 }//QhullPoint Coordinates
 
 #//!\name Conversions
 
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 std::vector QhullPoint::
 toStdVector() const
 {
     QhullPointIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//!\name GetSet
 
 //! QhullPoint is equal if it has the same address and dimension, or if the distance between the points is less than sqrt(qh_qh->distanceEpsilon())
 //! Uses sqrt() since distanceEpsilon is the roundoff for distance to hyperplane, i.e., the inner product
 bool QhullPoint::
 operator==(const QhullPoint &other) const
 {
     if(point_dimension!=other.point_dimension){
         return false;
     }
     const coordT *c= point_coordinates;
     const coordT *c2= other.point_coordinates;
     if(c==c2){
         return true;
     }
     if(!c || !c2 || !qh_qh){
         return false;
     }
     double dist2= 0.0;
     for(int k= point_dimension; k--; ){
         double diff= *c++ - *c2++;
         dist2 += diff*diff;
     }
     return (dist2 < qh_qh->distanceEpsilon()); // dist2 is distance()^2
 }//operator==
 
 #//!\name Methods
 
 //! Return distance between two points.
 double QhullPoint::
 distance(const QhullPoint &p) const
 {
     const coordT *c= point_coordinates;
     const coordT *c2= p.point_coordinates;
     int dim= point_dimension;
     if(dim!=p.point_dimension){
         throw QhullError(10075, "QhullPoint error: Expecting dimension %d for distance().  Got %d", dim, p.point_dimension);
     }
     if(!c || !c2){
         throw QhullError(10076, "QhullPoint error: Cannot compute distance() for undefined point");
     }
     double dist;
 
     switch(dim){
   case 2:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]);
       break;
   case 3:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]);
       break;
   case 4:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]);
       break;
   case 5:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]);
       break;
   case 6:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]);
       break;
   case 7:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]) + (c[6]-c2[6])*(c[6]-c2[6]);
       break;
   case 8:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]) + (c[6]-c2[6])*(c[6]-c2[6]) + (c[7]-c2[7])*(c[7]-c2[7]);
       break;
   default:
       dist= 0.0;
       for(int k=dim; k--; ){
           dist += (*c - *c2) * (*c - *c2);
           ++c;
           ++c2;
       }
       break;
     }
     return sqrt(dist);
 }//distance
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::ostream;
 using orgQhull::QhullPoint;
 
 //! Same as qh_printpointid [io.c]
 ostream &
 operator<<(ostream &os, const QhullPoint::PrintPoint &pr)
 {
     QhullPoint p= *pr.point; 
     countT i= p.id();
     if(pr.point_message){
         if(*pr.point_message){
             os << pr.point_message << " ";
         }
         if(pr.with_identifier && (i!=-1)){
             os << "p" << i << ": ";
         }
     }
     const realT *c= p.coordinates();
     for(int k=p.dimension(); k--; ){
         realT r= *c++;
         if(pr.point_message){
             os << " " << r; // FIXUP QH11010 %8.4g
         }else{
             os << " " << r; // FIXUP QH11010 qh_REAL_1
         }
     }
     os << std::endl;
     return os;
 }//printPoint
 
 ostream & 
 operator<<(ostream &os, const QhullPoint &p)
 {
     os << p.print(""); 
     return os;
 }//operator<<
diff --git a/src/libqhullcpp/QhullPoint.h b/src/libqhullcpp/QhullPoint.h
index 5416d6f..284dcf9 100644
--- a/src/libqhullcpp/QhullPoint.h
+++ b/src/libqhullcpp/QhullPoint.h
@@ -1,131 +1,131 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullPoint.h#15 $$Change: 1800 $
-** $DateTime: 2014/12/17 21:46:45 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullPoint.h#16 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHPOINT_H
 #define QHPOINT_H
 
 #include "QhullError.h"
 #include "QhullIterator.h"
 #include "QhullQh.h"
 #include "Coordinates.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Defined here
     class QhullPoint;  //!<  QhullPoint as a pointer and dimension to shared memory
     class QhullPointIterator; //!< Java-style iterator for QhullPoint coordinates
 
 #//!\name Used here
     class Qhull;
 
 //! A point in Qhull is an array of coordinates.
 class QhullPoint {
 
 #//!\name Iterators
 public:
     typedef coordT *                    base_type;  // for QhullPointSet
     typedef const coordT *              iterator;
     typedef const coordT *              const_iterator;
     typedef QhullPoint::iterator        Iterator;
     typedef QhullPoint::const_iterator  ConstIterator;
 
 #//!\name Fields
 protected: // For QhullPoints::iterator, QhullPoints::const_iterator
     coordT *            point_coordinates;  //!< Pointer to first coordinate,   0 if undefined
     QhullQh *           qh_qh;              //!< qhT for this instance of Qhull. 0 if undefined.  Used by id() and operator=()
     int                 point_dimension;    //!< Default dimension is qh_qh->hull_dim
 public:
 
 #//!\name Constructors
                         QhullPoint() : point_coordinates(0), qh_qh(0), point_dimension(0) {}
     explicit            QhullPoint(const Qhull &q);
                         QhullPoint(const Qhull &q, int pointDimension, coordT *c);
                         QhullPoint(const Qhull &q, coordT *c);
                         QhullPoint(const Qhull &q, Coordinates &c);
     explicit            QhullPoint(QhullQh *qh) : point_coordinates(0), qh_qh(qh), point_dimension(qh->hull_dim) {}
                         QhullPoint(QhullQh *qh, int pointDimension, coordT *c) : point_coordinates(c), qh_qh(qh), point_dimension(pointDimension) {}
                         QhullPoint(QhullQh *qh, coordT *c) : point_coordinates(c), qh_qh(qh), point_dimension(qh->hull_dim) {}
                         QhullPoint(QhullQh *qh, Coordinates &c) : point_coordinates(c.data()), qh_qh(qh), point_dimension(c.count()) {}
                         // Creates an alias.  Does not copy the point.  Needed for return by value and parameter passing.
                         QhullPoint(const QhullPoint &other) : point_coordinates(other.point_coordinates), point_dimension(other.point_dimension), qh_qh(other.qh_qh) {}
                         // Creates an alias.  Does not copy the point.  Needed for vector
     QhullPoint &        operator=(const QhullPoint &other) { point_coordinates= other.point_coordinates; point_dimension= other.point_dimension; qh_qh= other.qh_qh; return *this; }
                         ~QhullPoint() {}
 
 
 #//!\name Conversions
 
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList       toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
 public:
     const coordT *      coordinates() const { return point_coordinates; }  //!< 0 if undefined
     coordT *            coordinates() { return point_coordinates; }        //!< 0 if undefined
     void                defineAs(int pointDimension, coordT *c) { QHULL_ASSERT(pointDimension>=0); point_coordinates= c; point_dimension= pointDimension; }
     //! Creates an alias, but does not change qh()
     void                defineAs(QhullPoint &other) { point_coordinates= other.point_coordinates; point_dimension= other.point_dimension; }
     int                 dimension() const { return point_dimension; }
     coordT *            getBaseT() const { return point_coordinates; } // for QhullSet
     countT              id() const { return qh_pointid(qh_qh, point_coordinates); } // NOerrors
     bool                isDefined() const { return (point_coordinates!=0 && point_dimension>0); };
     bool                operator==(const QhullPoint &other) const;
     bool                operator!=(const QhullPoint &other) const { return !operator==(other); }
     const coordT &      operator[](int idx) const { QHULL_ASSERT(point_coordinates!=0 && idx>=0 && idx=0 && idx
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Conversions
 
 /************** FIXUP
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 std::vector QhullPointSet::
 toStdVector() const
 {
     QhullPointSetIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//!\name GetSet
 
 bool QhullPointSet::
 operator==(const QhullPointSet &o) const
 {
     if(dimension()!=o.dimension() || count()!=o.count()){
         return false;
     }
     QhullPointSetIterator i(*this);
     QhullPointSetIterator j(o);
     while(i.hasNext()){
         if(i.next()!=j.next()){
             return false;
         }
     }
     return true;
 }//operator==
 
 //! Derived from QhullSet::value
 //! Returns QhullPoint() on error
 QhullPoint QhullPointSet::
 value(countT idx) const
 {
     // Avoid error in qh_setsize() and assert in elementPointer()
     //const T *n= reinterpret_cast(&SETelem_(getSetT(), idx));
     void **n= reinterpret_cast(&SETelem_(getSetT(), idx));
     coordT **n2= reinterpret_cast(n);
     if(idx>=0 && n(&SETelem_(getSetT(), idx));
     coordT **n2= reinterpret_cast(n);
     if(idx>=0 && nconstEnd()){
         if(*i++ == p){
             return true;
         }
     }
     return false;
 }//findNext
 
 bool QhullPointSetIterator::
 findPrevious(const QhullPoint &p)
 {
     while(i!=c->constBegin()){
         if(*(--i) == p){
             return true;
         }
     }
     return false;
 }//findPrevious
 */
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::QhullPointSet;
 using orgQhull::QhullPointSetIterator;
 
 ostream &
 operator<<(ostream &os, const QhullPointSet::PrintIdentifiers &pr)
 {
     os << pr.print_message;
     const QhullPointSet s= *pr.point_set;
     QhullPointSetIterator i(s);
     while(i.hasNext()){
         if(i.hasPrevious()){
             os << " ";
         }
         const QhullPoint point= i.next();
         countT id= point.id();
         os << "p" << id;
 
     }
     os << endl;
     return os;
 }//PrintIdentifiers
 
 ostream &
 operator<<(ostream &os, const QhullPointSet::PrintPointSet &pr)
 {
     os << pr.print_message;
     const QhullPointSet s= *pr.point_set;
     for(QhullPointSet::const_iterator i=s.begin(); i != s.end(); ++i){
         const QhullPoint point= *i;
         os << point;
     }
     return os;
 }//printPointSet
 
 
diff --git a/src/libqhullcpp/QhullPointSet.h b/src/libqhullcpp/QhullPointSet.h
index 4de94ce..a04d8c0 100644
--- a/src/libqhullcpp/QhullPointSet.h
+++ b/src/libqhullcpp/QhullPointSet.h
@@ -1,78 +1,78 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullPointSet.h#14 $$Change: 1801 $
-** $DateTime: 2014/12/17 22:37:12 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullPointSet.h#15 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLPOINTSET_H
 #define QHULLPOINTSET_H
 
 #include "QhullSet.h"
 #include "QhullPoint.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Used here
     class Qhull;
     class QhullPoint;
 
 #//!\name Defined here
     //! QhullPointSet -- a set of coordinate pointers with input dimension
     // with const_iterator and iterator
     class QhullPointSet;
 
 class QhullPointSet : public QhullSet {
 
 private:
 #//!\name Fields
     // no fields
 public:
 
 #//!\name Construct
                         QhullPointSet(const Qhull &q, setT *s) : QhullSet(q, s) {}
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                         QhullPointSet(QhullQh *qh, setT *s) : QhullSet(qh, s) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullPointSet(const QhullPointSet &other) : QhullSet(other) {}
     QhullPointSet &     operator=(const QhullPointSet &other) { QhullSet::operator=(other); }
                         ~QhullPointSet() {}
 
                         //!Default constructor disabled.
 private:
                         QhullPointSet();
 public:
 
 #//!\name IO
     struct PrintIdentifiers{
         const QhullPointSet *point_set;
         const char *    print_message;
         PrintIdentifiers(const char *message, const QhullPointSet *s) : point_set(s), print_message(message) {}
     };//PrintIdentifiers
     PrintIdentifiers printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }
 
     struct PrintPointSet{
         const QhullPointSet *point_set;
         const char *    print_message;
         PrintPointSet(const char *message, const QhullPointSet &s) : point_set(&s), print_message(message) {}
     };//PrintPointSet
     PrintPointSet       print(const char *message) const { return PrintPointSet(message, *this); }
 
 };//QhullPointSet
 
 typedef QhullSetIterator  QhullPointSetIterator;
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet::PrintIdentifiers &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet::PrintPointSet &pr);
 
 #endif // QHULLPOINTSET_H
diff --git a/src/libqhullcpp/QhullPoints.cpp b/src/libqhullcpp/QhullPoints.cpp
index fe95c18..f49e9ab 100644
--- a/src/libqhullcpp/QhullPoints.cpp
+++ b/src/libqhullcpp/QhullPoints.cpp
@@ -1,303 +1,303 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullPoints.cpp#10 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullPoints.cpp#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullPoints.h"
 #include "Qhull.h"
 
 #include 
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Constructors
 
 QhullPoints::
 QhullPoints(const Qhull &q) 
 : point_first(0)
 , point_end(0)
 , qh_qh(q.qh())
 , point_dimension(q.hullDimension())
 {
 }//QhullPoints Qhull
 
 QhullPoints::
 QhullPoints(const Qhull &q, int pointDimension) 
 : point_first(0)
 , point_end(0)
 , qh_qh(q.qh())
 , point_dimension(pointDimension)
 {
     QHULL_ASSERT(pointDimension>=0);
 }//QhullPoints Qhull dim
 
 QhullPoints::
 QhullPoints(const Qhull &q, int pointDimension, countT coordinateCount2, coordT *c) 
 : point_first(c)
 , point_end(c+coordinateCount2)
 , qh_qh(q.qh())
 , point_dimension(pointDimension)
 {
     QHULL_ASSERT(pointDimension>=0);
     QHULL_ASSERT(coordinateCount2>=0);
 }//QhullPoints Qhull dim coordT
 
 QhullPoints::
 QhullPoints(QhullQh *qh, int pointDimension, countT coordinateCount2, coordT *c) 
 : point_first(c)
 , point_end(c+coordinateCount2)
 , qh_qh(qh)
 , point_dimension(pointDimension)
 {
     QHULL_ASSERT(pointDimension>=0);
     QHULL_ASSERT(coordinateCount2>=0);
 }//QhullPoints QhullQh dim coordT
 
 #//!\name Conversions
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 std::vector QhullPoints::
 toStdVector() const
 {
     QhullPointsIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//!\name GetSet
 
 countT QhullPoints::
 extraCoordinatesCount() const
 {
     if(point_dimension>0){
         return (countT)((point_end-point_first)%(size_t)point_dimension);
     }
     return 0;
 }//extraCoordinatesCount
 
 //! QhullPoints is equal if the same address, or if the coordinates are identical
 //! Use QhullPoint.operator==() for DISTround equality
 bool QhullPoints::
 operator==(const QhullPoints &other) const
 {
     if((point_end-point_first) != (other.point_end-other.point_first)){
         return false;
     }
     if(point_first==other.point_first){
         return true;
     }
     const coordT *c= point_first;
     const coordT *c2= other.point_first;
     while(c=0 && idxhull_dim, point_first+idx*qh_qh->hull_dim);
     }
     return p;
 }//value
 
 QhullPoint QhullPoints::
 value(countT idx, QhullPoint &defaultValue) const
 {
     QhullPoint p(qh_qh);
     if(idx>=0 && idxhull_dim, point_first+idx*qh_qh->hull_dim);
     }else{
         p.defineAs(defaultValue);
     }
     return p;
 }//value
 
 #//! Methods
 
 bool QhullPoints::
 contains(const QhullPoint &t) const
 {
     const_iterator i= begin();
     while(i != end()){
         if(*i==t){
             return true;
         }
         i++;
     }
     return false;
 }//contains
 
 countT QhullPoints::
 count(const QhullPoint &t) const
 {
     countT n= 0;
     const_iterator i= begin();
     while(i != end()){
         if(*i==t){
             ++n;
         }
         i++;
     }
     return n;
 }//count
 
 countT QhullPoints::
 indexOf(const coordT *pointCoordinates) const
 {
     if(!includesCoordinates(pointCoordinates) || point_dimension==0){
         return -1;
     }
     size_t offset= pointCoordinates-point_first;
     countT idx= (countT)(offset/(size_t)point_dimension);
     countT extra= (countT)(offset%(size_t)point_dimension);
     if(extra!=0){
         throw QhullError(10066, "Qhull error: coordinates %x are not at point boundary (extra %d at index %d)", extra, idx, 0.0, pointCoordinates);
     }
     return idx;
 }//indexOf coordT
 
 countT QhullPoints::
 indexOf(const coordT *pointCoordinates, int noThrow) const
 {
     size_t extra= 0;
     if(noThrow){
         if(!includesCoordinates(pointCoordinates) || point_dimension==0){
             return -1;
         }
         extra= (pointCoordinates-point_first)%(size_t)point_dimension;
     }
     return indexOf(pointCoordinates-extra);
 }//indexOf coordT noThrow
 
 countT QhullPoints::
 indexOf(const QhullPoint &t) const
 {
     countT j=0;
     const_iterator i= begin();
     while(i!=end()){
         if(*i==t){
             return j;
         }
         ++i;
         ++j;
     }
     return -1;
 }//indexOf
 
 countT QhullPoints::
 lastIndexOf(const QhullPoint &t) const
 {
     countT j= count();
     const_iterator i= end();
     while(i != begin()){
         --i;
         --j;
         if(*i==t){
             return j;
         }
     }
     return -1;
 }//lastIndexOf
 
 QhullPoints QhullPoints::
 mid(countT idx, countT length) const
 {
     countT n= count();
     if(idx<0 || idx>=n){
         n= 0;
     }else if(length<0 || idx+length>=n){
         n -= idx;
     }else{
         n -= idx+length;
     }
     return QhullPoints(qh_qh, qh_qh->hull_dim, n*qh_qh->hull_dim, point_first+idx*qh_qh->hull_dim);
 }//mid
 
 #//!\name QhullPointsIterator
 
 bool QhullPointsIterator::
 findNext(const QhullPoint &p)
 {
     while(i!=ps->constEnd()){
         if(*i++ == p){
             return true;
         }
     }
     return false;
 }//findNext
 
 bool QhullPointsIterator::
 findPrevious(const QhullPoint &p)
 {
     while(i!=ps->constBegin()){
         if(*--i == p){
             return true;
         }
     }
     return false;
 }//findPrevious
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::QhullPoints;
 using orgQhull::QhullPointsIterator;
 
 ostream &
 operator<<(ostream &os, const QhullPoints &p)
 {
     QhullPointsIterator i(p);
     while(i.hasNext()){
         os << i.next();
     }
     return os;
 }//operator<
 
 namespace orgQhull {
 
 #//!\name Defined here
     class QhullPoints;          //!< One or more points Coordinate pointers with dimension and iterators
     class QhullPointsIterator;  //!< Java-style iterator
 
 class QhullPoints {
 
 private:
 #//!\name Fields
     coordT *            point_first; //!< First coordinate of an array of points of point_dimension
     coordT *            point_end;   //!< End of point coordinates (end>=first).  Trailing coordinates ignored
     QhullQh *           qh_qh;       //!< Maybe initialized NULL to allow ownership by RboxPoints
     int                 point_dimension;  //!< Dimension, >=0
 
 public:
 #//!\name Subtypes
     class const_iterator;
     class iterator;
     typedef QhullPoints::const_iterator ConstIterator;
     typedef QhullPoints::iterator       Iterator;
 
 #//!\name Construct
     explicit            QhullPoints(const Qhull &q);
                         QhullPoints(const Qhull &q, int pointDimension);
                         QhullPoints(const Qhull &q, int pointDimension, countT coordinateCount2, coordT *c);
     explicit            QhullPoints(QhullQh *qh) : point_first(0), point_end(0), qh_qh(qh), point_dimension(qh ? qh->hull_dim : 0) {}
                         QhullPoints(QhullQh *qh, int pointDimension) : point_first(0), point_end(0), qh_qh(qh), point_dimension(pointDimension) { QHULL_ASSERT(pointDimension>=0); }
                         QhullPoints(QhullQh *qh, int pointDimension, countT coordinateCount2, coordT *c);
                         //! Copy constructor copies pointers but not contents.  Needed for return by value and parameter passing.
                         QhullPoints(const QhullPoints &other)  : point_first(other.point_first), point_end(other.point_end), qh_qh(other.qh_qh), point_dimension(other.point_dimension) {}
     QhullPoints &       operator=(const QhullPoints &other) { point_first= other.point_first; point_end= other.point_end; qh_qh= other.qh_qh; point_dimension= other.point_dimension; return *this; }
                         ~QhullPoints() {}
 
 public:
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList   toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     QhullPoint          at(countT idx) const { /* point_first==0 caught by point_end assert */ coordT *p= point_first+idx*point_dimension; QHULL_ASSERT(p=0 && c!=0) || (c==0 && coordinatesCount==0)); point_first= c; point_end= c+coordinatesCount; }
     void                defineAs(const QhullPoints &other) { point_first= other.point_first; point_end= other.point_end; qh_qh= other.qh_qh; point_dimension= other.point_dimension; }
     int                 dimension() const { return point_dimension; }
     ConstIterator       end() const { return ConstIterator(qh_qh, point_end); }
     Iterator            end() { return Iterator(qh_qh, point_end); }
     coordT *            extraCoordinates() const { return extraCoordinatesCount() ? (point_end-extraCoordinatesCount()) : 0; }
     countT              extraCoordinatesCount() const;  // WARN64
     QhullPoint          first() const { return QhullPoint(qh_qh, point_dimension, point_first); }
     QhullPoint          front() const { return first(); }
     bool                includesCoordinates(const coordT *c) const { return c>=point_first && c(other)); return *this; }
  
         QhullPoint *    operator->() { return this; }
         // value instead of reference since advancePoint() modifies self
         QhullPoint      operator*() const { return *this; }
         QhullPoint      operator[](countT idx) const { QhullPoint n= *this; n.advancePoint(idx); return n; }
         bool            operator==(const iterator &o) const { return point_coordinates==o.point_coordinates; }
         bool            operator!=(const iterator &o) const { return !operator==(o); }
         bool            operator<(const iterator &o) const  { return point_coordinates < o.point_coordinates; }
         bool            operator<=(const iterator &o) const { return point_coordinates <= o.point_coordinates; }
         bool            operator>(const iterator &o) const  { return point_coordinates > o.point_coordinates; }
         bool            operator>=(const iterator &o) const { return point_coordinates >= o.point_coordinates; }
         // reinterpret_cast to break circular dependency
         bool            operator==(const QhullPoints::const_iterator &o) const { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates==reinterpret_cast(o).point_coordinates; }
         bool            operator!=(const QhullPoints::const_iterator &o) const { return !operator==(reinterpret_cast(o)); }
         bool            operator<(const QhullPoints::const_iterator &o) const  { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates < reinterpret_cast(o).point_coordinates; }
         bool            operator<=(const QhullPoints::const_iterator &o) const { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates <= reinterpret_cast(o).point_coordinates; }
         bool            operator>(const QhullPoints::const_iterator &o) const  { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates > reinterpret_cast(o).point_coordinates; }
         bool            operator>=(const QhullPoints::const_iterator &o) const { QHULL_ASSERT(qh_qh==reinterpret_cast(o).qh_qh); return point_coordinates >= reinterpret_cast(o).point_coordinates; }
         iterator &      operator++() { advancePoint(1); return *this; }
         iterator        operator++(int) { iterator n= *this; operator++(); return iterator(n); }
         iterator &      operator--() { advancePoint(-1); return *this; }
         iterator        operator--(int) { iterator n= *this; operator--(); return iterator(n); }
         iterator &      operator+=(countT idx) { advancePoint(idx); return *this; }
         iterator &      operator-=(countT idx) { advancePoint(-idx); return *this; }
         iterator        operator+(countT idx) const { iterator n= *this; n.advancePoint(idx); return n; }
         iterator        operator-(countT idx) const { iterator n= *this; n.advancePoint(-idx); return n; }
         difference_type operator-(iterator o) const { QHULL_ASSERT(qh_qh==o.qh_qh && point_dimension==o.point_dimension); return (point_dimension ? (point_coordinates-o.point_coordinates)/point_dimension : 0); }
     };//QhullPoints::iterator
 
 #//!\name QhullPoints::const_iterator
     //!\todo FIXUP QH11018 const_iterator same as iterator
     class const_iterator : public QhullPoint {
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef QhullPoint          value_type;
         typedef const value_type *  pointer;
         typedef const value_type &  reference;
         typedef ptrdiff_t           difference_type;
 
                         const_iterator(const QhullPoints::iterator &o) : QhullPoint(*o) {}
         explicit        const_iterator(const QhullPoints &ps) : QhullPoint(ps.qh(), ps.dimension(), ps.coordinates()) {}
                         const_iterator(const Qhull &q, coordT *c): QhullPoint(q, c) {}
                         const_iterator(const Qhull &q, int pointDimension, coordT *c): QhullPoint(q, pointDimension, c) {}
                         const_iterator(QhullQh *qh, coordT *c): QhullPoint(qh, c) {}
                         const_iterator(QhullQh *qh, int pointDimension, coordT *c): QhullPoint(qh, pointDimension, c) {}
                         const_iterator(const const_iterator &o) : QhullPoint(*o) {}
         const_iterator &operator=(const const_iterator &o) { defineAs(const_cast(o)); return *this; }
 
         // value/non-const since advancePoint(1), etc. modifies self
         QhullPoint      operator*() const { return *this; }
         QhullPoint *    operator->() { return this; }
         QhullPoint      operator[](countT idx) const { QhullPoint n= *this; n.advancePoint(idx); return n; }
         bool            operator==(const const_iterator &o) const { return point_coordinates==o.point_coordinates; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
         bool            operator<(const const_iterator &o) const  { return point_coordinates < o.point_coordinates; }
         bool            operator<=(const const_iterator &o) const { return point_coordinates <= o.point_coordinates; }
         bool            operator>(const const_iterator &o) const  { return point_coordinates > o.point_coordinates; }
         bool            operator>=(const const_iterator &o) const { return point_coordinates >= o.point_coordinates; }
         const_iterator &operator++() { advancePoint(1); return *this; }
         const_iterator  operator++(int) { const_iterator n= *this; operator++(); return const_iterator(n); }
         const_iterator &operator--() { advancePoint(-1); return *this; }
         const_iterator  operator--(int) { const_iterator n= *this; operator--(); return const_iterator(n); }
         const_iterator &operator+=(countT idx) { advancePoint(idx); return *this; }
         const_iterator &operator-=(countT idx) { advancePoint(-idx); return *this; }
         const_iterator  operator+(countT idx) const { const_iterator n= *this; n.advancePoint(idx); return n; }
         const_iterator  operator-(countT idx) const { const_iterator n= *this; n.advancePoint(-idx); return n; }
         difference_type operator-(const_iterator o) const { QHULL_ASSERT(qh_qh==o.qh_qh && point_dimension==o.point_dimension); return (point_dimension ? (point_coordinates-o.point_coordinates)/point_dimension : 0); }
     };//QhullPoints::const_iterator
 
 #//!\name IO
     struct PrintPoints{
         const QhullPoints  *points;
         const char *    point_message;
         bool            with_identifier;
         PrintPoints(const char *message, bool withIdentifier, const QhullPoints &ps) : points(&ps), point_message(message), with_identifier(withIdentifier) {}
     };//PrintPoints
     PrintPoints          print() const { return  PrintPoints("", false, *this); }
     PrintPoints          print(const char *message) const { return PrintPoints(message, false, *this); }
     PrintPoints          printWithIdentifier(const char *message) const { return PrintPoints(message, true, *this); }
     //FIXUP remove message for print()?
 };//QhullPoints
 
 // Instead of QHULL_DECLARE_SEQUENTIAL_ITERATOR because next(),etc would return a reference to a temporary
 class QhullPointsIterator
 {
     typedef QhullPoints::const_iterator const_iterator;
 
 #//!\name Fields
 private:
     const QhullPoints  *ps;
     const_iterator      i;
 
 public:
                         QhullPointsIterator(const QhullPoints &other) : ps(&other), i(ps->constBegin()) {}
     QhullPointsIterator &operator=(const QhullPoints &other) { ps = &other; i = ps->constBegin(); return *this; }
 
     bool                findNext(const QhullPoint &t);
     bool                findPrevious(const QhullPoint &t);
     bool                hasNext() const { return i != ps->constEnd(); }
     bool                hasPrevious() const { return i != ps->constBegin(); }
     QhullPoint          next() { return *i++; }
     QhullPoint          peekNext() const { return *i; }
     QhullPoint          peekPrevious() const { const_iterator p = i; return *--p; }
     QhullPoint          previous() { return *--i; }
     void                toBack() { i = ps->constEnd(); }
     void                toFront() { i = ps->constBegin(); }
 };//QhullPointsIterator
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &          operator<<(std::ostream &os, const orgQhull::QhullPoints &p);
 std::ostream &          operator<<(std::ostream &os, const orgQhull::QhullPoints::PrintPoints &pr);
 
 #endif // QHULLPOINTS_H
diff --git a/src/libqhullcpp/QhullQh.cpp b/src/libqhullcpp/QhullQh.cpp
index 3e03c81..13022fd 100644
--- a/src/libqhullcpp/QhullQh.cpp
+++ b/src/libqhullcpp/QhullQh.cpp
@@ -1,223 +1,223 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullQh.cpp#8 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullQh.cpp#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullQh -- Qhull's global data structure, qhT, as a C++ class
 
 
 
 #include "QhullError.h"
 #include "QhullQh.h"
 #include "QhullStat.h"
 #include "Qhull.h"
 
 #include 
 #include 
 
 #include 
 
 using std::cerr;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//Global variables
 const double QhullQh::
 default_factor_epsilon= 1.0;
 
 #//Constructor, destructor, etc.
 
 //! Derived from qh_new_qhull[user.c]
 QhullQh::
 QhullQh()
 : qhull_status(qh_ERRnone)
 , qhull_message()
 , error_stream(0)
 , output_stream(0)
 , factor_epsilon(QhullQh::default_factor_epsilon)
 , useOutputStream(false)
 {
     // NOerrors -- Does not call qh_errexit()
     qh_meminit(this, NULL);
     this->ISqhullQh= True;
     // NOerrors -- Does not call qh_errexit()
     qh_initstatistics(this);
     // NOerrors -- Does not call qh_errexit()
     qh_initqhull_start2(this, NULL, NULL, qh_FILEstderr);
 }//QhullQh
 
 QhullQh::
 ~QhullQh()
 {
     qh_freeqhull(this, qh_ALL); // sets qh.NOerrexit. Clears struct *qh_qh including run_id
 }//~QhullQh
 
 #//!\name Methods
 
 void QhullQh::
 checkAndFreeQhullMemory()
 {
 #ifdef qh_NOmem
     qh_freeqhull(this, qh_ALL);
 #else
     qh_freeqhull(this, !qh_ALL);
     countT curlong;
     countT totlong;
     qh_memfreeshort(this, &curlong, &totlong);
     if (curlong || totlong)
         throw QhullError(10026, "Qhull error: qhull did not free %d bytes of long memory (%d pieces).", totlong, curlong);
 #endif
 }//checkAndFreeQhullMemory
 
 #//Messaging
 
 void QhullQh::
 appendQhullMessage(const string &s)
 {
     if(output_stream && useOutputStream && this->USEstdout){ 
         *output_stream << s;
     }else if(error_stream){
         *error_stream << s;
     }else{
         qhull_message += s;
     }
 }//appendQhullMessage
 
 //! clearQhullMessage does not throw errors (~Qhull)
 void QhullQh::
 clearQhullMessage()
 {
     qhull_status= qh_ERRnone;
     qhull_message.clear();
     RoadError::clearGlobalLog();
 }//clearQhullMessage
 
 //! hasQhullMessage does not throw errors (~Qhull)
 bool QhullQh::
 hasQhullMessage() const
 {
     return (!qhull_message.empty() || qhull_status!=qh_ERRnone);
     //FIXUP QH11006 -- inconsistent usage with Rbox.  hasRboxMessage just tests rbox_status.  No appendRboxMessage()
 }
 
 void QhullQh::
 maybeThrowQhullMessage(int exitCode)
 {
     if(qhull_status==qh_ERRnone){
         qhull_status= exitCode;
     }
     if(qhull_status!=qh_ERRnone){
         QhullError e(qhull_status, qhull_message);
         clearQhullMessage();
         throw e; // FIXUP QH11007: copy constructor is expensive if logging
     }
 }//maybeThrowQhullMessage
 
 void QhullQh::
 maybeThrowQhullMessage(int exitCode, int noThrow)  throw()
 {
     QHULL_UNUSED(noThrow);
 
     if(qhull_status==qh_ERRnone){
         qhull_status= exitCode;
     }
     if(qhull_status!=qh_ERRnone){
         QhullError e(qhull_status, qhull_message);
         e.logError();
     }
 }//maybeThrowQhullMessage
 
 //! qhullMessage does not throw errors (~Qhull)
 std::string QhullQh::
 qhullMessage() const
 {
     if(qhull_message.empty() && qhull_status!=qh_ERRnone){
         return "qhull: no message for error.  Check cerr or error stream\n";
     }else{
         return qhull_message;
     }
 }//qhullMessage
 
 int QhullQh::
 qhullStatus() const
 {
     return qhull_status;
 }//qhullStatus
 
 void QhullQh::
 setErrorStream(ostream *os)
 {
     error_stream= os;
 }//setErrorStream
 
 //! Updates useOutputStream
 void QhullQh::
 setOutputStream(ostream *os)
 {
     output_stream= os;
     useOutputStream= (os!=0);
 }//setOutputStream
 
 }//namespace orgQhull
 
 /*---------------------------------
 
   qh_fprintf(qhT *qh, fp, msgcode, format, list of args )
     FIXUP s_qhull_output vs. fp is ignored (replaces qh_fprintf() in userprintf_r.c)
 
 notes:
     only called from libqhull
     same as fprintf() and RboxPoints.qh_fprintf_rbox()
     fgets() is not trapped like fprintf()
     Do not throw errors from here.  Use qh_errexit;
 */
 extern "C"
 void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {
     va_list args;
 
     using namespace orgQhull;
 
     if(!qh->ISqhullQh){
         fprintf(stderr, "QH10025 Qhull error: qh_fprintf called from a Qhull instance without QhullQh defined\n");
         qh_exit(10025);
     }
     QhullQh *qhullQh= static_cast(qh);
     va_start(args, fmt);
     if(msgcode=MSG_ERROR && msgcodeqhull_statusqhull_status>=MSG_WARNING){
                 qhullQh->qhull_status= msgcode;
             }
         }
         char newMessage[MSG_MAXLEN];
         // RoadError will add the message tag
         vsnprintf(newMessage, sizeof(newMessage), fmt, args);
         qhullQh->appendQhullMessage(newMessage);
         va_end(args);
         return;
     }
     if(qhullQh->output_stream && qhullQh->useOutputStream){
         char newMessage[MSG_MAXLEN];
         vsnprintf(newMessage, sizeof(newMessage), fmt, args);
         *qhullQh->output_stream << newMessage;
         va_end(args);
         return;
     }
     // FIXUP QH11008: how do users trap messages and handle input?  A callback?
     char newMessage[MSG_MAXLEN];
     vsnprintf(newMessage, sizeof(newMessage), fmt, args);
     qhullQh->appendQhullMessage(newMessage);
     va_end(args);
 } /* qh_fprintf */
diff --git a/src/libqhullcpp/QhullQh.h b/src/libqhullcpp/QhullQh.h
index a375b80..f7c2a6f 100644
--- a/src/libqhullcpp/QhullQh.h
+++ b/src/libqhullcpp/QhullQh.h
@@ -1,111 +1,111 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullQh.h#13 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullQh.h#14 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLQH_H
 #define QHULLQH_H
 
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  /* interaction between '_setjmp' and C++ object destruction is non-portable */
 /* setjmp should not be implemented with 'catch' */
 #endif
 
 //! QH_TRY_(qh_qh){ // no object creation -- destructors skipped on longjmp()
 //! }
 //! qh->maybeThrowQhullMessage(QH_TRY_status);
 
 #define QH_TRY_ERROR 10071
 
 #define QH_TRY_(qh) \
     int QH_TRY_status; \
     if(qh->NOerrexit){ \
         qh->NOerrexit= False; \
         QH_TRY_status= setjmp(qh->errexit); \
     }else{ \
         throw QhullError(QH_TRY_ERROR, "Already inside a QH_TRY_().  qh.NOerrexit is false"); \
     } \
     if(!QH_TRY_status) 
 
 #define QH_TRY_NO_THROW_(qh) \
     int QH_TRY_status; \
     if(qh->NOerrexit){ \
         qh->NOerrexit= False; \
         QH_TRY_status= setjmp(qh->errexit); \
     }else{ \
         QH_TRY_status= QH_TRY_ERROR; \
     } \
     if(!QH_TRY_status) 
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! QhullQh -- Qhull's global data structure, qhT, as a C++ class
     class QhullQh;
 
 //! POD type equivalent to qhT.  No virtual members
 class QhullQh : public qhT {
 
 #//!\name Constants
 
 #//!\name Fields 
 private:
     int                 qhull_status;   //! qh_ERRnone if valid
     std::string         qhull_message;  //! Returned messages from libqhull_r
     std::ostream *      error_stream;   //! overrides errorMessage, use appendQhullMessage()
     std::ostream *      output_stream;  //! send output to stream
     double              factor_epsilon; //!< Factor to increase ANGLEround and DISTround for hyperplane equality
 
     friend void         ::qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
     
     static const double default_factor_epsilon;  //!< Default factor_epsilon is 1.0
 
 #//!\name Attribute
 public:
     bool                useOutputStream; //! Set if using outputStream
     // FIXUP QH11003 feasiblePoint useOutputStream as field or getter?
 
 #//!\name Constructors
 public:
                         QhullQh();
                         ~QhullQh();
 private:
                         //!disable copy constructor and assignment
                         QhullQh(const QhullQh &);
     QhullQh &           operator=(const QhullQh &);
 public:
 
 #//!\name GetSet
     double              factorEpsilon() const { return factor_epsilon; }
     void                setFactorEpsilon(double a) { factor_epsilon= a; }
 
 #//!\name Messaging
     void                appendQhullMessage(const std::string &s);
     void                clearQhullMessage();
     std::string         qhullMessage() const;
     bool                hasQhullMessage() const;
     void                maybeThrowQhullMessage(int exitCode);
     void                maybeThrowQhullMessage(int exitCode, int noThrow) throw();
     int                 qhullStatus() const;
     void                setErrorStream(std::ostream *os);
     void                setOutputStream(std::ostream *os);
 
 #//!\name Methods
     double              angleEpsilon() const { return this->ANGLEround*factor_epsilon; } //!< Epsilon for hyperplane angle equality
     void                checkAndFreeQhullMemory();
     double              distanceEpsilon() const { return this->DISTround*factor_epsilon; } //!< Epsilon for distance to hyperplane
 
 };//class QhullQh
 
 }//namespace orgQhull
 
 #endif // QHULLQH_H
diff --git a/src/libqhullcpp/QhullRidge.cpp b/src/libqhullcpp/QhullRidge.cpp
index 610dd61..5f87208 100644
--- a/src/libqhullcpp/QhullRidge.cpp
+++ b/src/libqhullcpp/QhullRidge.cpp
@@ -1,110 +1,110 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullRidge.cpp#8 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullRidge.cpp#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullRidge -- Qhull's ridge structure, ridgeT, as a C++ class
 
 #include "QhullSets.h"
 #include "QhullVertex.h"
 #include "QhullRidge.h"
 #include "Qhull.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//!\name Class objects
 ridgeT QhullRidge::
 s_empty_ridge= {0,0,0,0,0,
                 0,0};
 
 #//!\name Constructors
 
 QhullRidge::QhullRidge(const Qhull &q)
 : qh_ridge(&s_empty_ridge)
 , qh_qh(q.qh())
 {
 }//Default
 
 QhullRidge::QhullRidge(const Qhull &q, ridgeT *r)
 : qh_ridge(r ? r : &s_empty_ridge)
 , qh_qh(q.qh())
 {
 }//ridgeT
 
 #//!\name foreach
 
 //! Return True if nextRidge3d
 //! Simplicial facets may have incomplete ridgeSets
 //! Does not use qh_errexit()
 bool QhullRidge::
 hasNextRidge3d(const QhullFacet &f) const
 {
     vertexT *v= 0;
     ridgeT *ridge= qh_nextridge3d(qh_qh, getRidgeT(), f.getFacetT(), &v);
     return (ridge!=0);
 }//hasNextRidge3d
 
 //! Return next ridge and optional vertex for a 3d facet and ridge
 //! Does not use qh_errexit()
 QhullRidge QhullRidge::
 nextRidge3d(const QhullFacet &f, QhullVertex *nextVertex) const
 {
     vertexT *v= 0;
     ridgeT *ridge= qh_nextridge3d(qh_qh, getRidgeT(), f.getFacetT(), &v);
     if(!ridge){
         throw QhullError(10030, "Qhull error nextRidge3d:  missing next ridge for facet %d ridge %d.  Does facet contain ridge?", f.id(), id());
     }
     if(nextVertex!=0){
         *nextVertex= QhullVertex(qh_qh, v);
     }
     return QhullRidge(qh_qh, ridge);
 }//nextRidge3d
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullRidge;
 using orgQhull::QhullVertex;
 
 ostream &
 operator<<(ostream &os, const QhullRidge &r)
 {
     os << r.print("");
     return os;
 }//<< QhullRidge
 
 //! Duplicate of qh_printridge [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullRidge::PrintRidge &pr)
 {
     os << pr.print_message;
     QhullRidge r= *pr.ridge;
     os << "     - r" << r.id();
     if(r.getRidgeT()->tested){
         os << " tested";
     }
     if(r.getRidgeT()->nonconvex){
         os << " nonconvex";
     }
     os << endl;
     os << r.vertices().print("           vertices:");
     if(r.getRidgeT()->top && r.getRidgeT()->bottom){
         os << "           between f" << r.topFacet().id() << " and f" << r.bottomFacet().id() << endl;
     }else if(r.getRidgeT()->top){
         os << "           top f" << r.topFacet().id() << endl;
     }else if(r.getRidgeT()->bottom){
         os << "           bottom f" << r.bottomFacet().id() << endl;
     }
 
     return os;
 }//<< PrintRidge
diff --git a/src/libqhullcpp/QhullRidge.h b/src/libqhullcpp/QhullRidge.h
index d1fb3bd..c19befa 100644
--- a/src/libqhullcpp/QhullRidge.h
+++ b/src/libqhullcpp/QhullRidge.h
@@ -1,113 +1,113 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullRidge.h#11 $$Change: 1800 $
-** $DateTime: 2014/12/17 21:46:45 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullRidge.h#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLRIDGE_H
 #define QHULLRIDGE_H
 
 #include "QhullSet.h"
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 #include "QhullFacet.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Used here
     class Qhull;
     class QhullVertex;
     class QhullVertexSet;
     class QhullFacet;
 
 #//!\name Defined here
     //! QhullRidge -- Qhull's ridge structure, ridgeT [libqhull.h], as a C++ class
     class QhullRidge;
     typedef QhullSet  QhullRidgeSet;
     typedef QhullSetIterator  QhullRidgeSetIterator;
     // see QhullSets.h for QhullRidgeSet and QhullRidgeSetIterator -- avoids circular references
 
 /************************
 a ridge is hull_dim-1 simplex between two neighboring facets.  If the
 facets are non-simplicial, there may be more than one ridge between
 two facets.  E.G. a 4-d hypercube has two triangles between each pair
 of neighboring facets.
 
 topological information:
     vertices            a set of vertices
     top,bottom          neighboring facets with orientation
 
 geometric information:
     tested              True if ridge is clearly convex
     nonconvex           True if ridge is non-convex
 */
 
 class QhullRidge {
 
 #//!\name Defined here
 public:
     typedef ridgeT *   base_type;  // for QhullRidgeSet
 
 #//!\name Fields
 private:
     ridgeT *            qh_ridge;
     QhullQh *           qh_qh;
 
 #//!\name Class objects
     static ridgeT       s_empty_ridge;
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
     explicit            QhullRidge(const Qhull &q);
                         QhullRidge(const Qhull &q, ridgeT *r);
     explicit            QhullRidge(QhullQh *qh) : qh_ridge(&s_empty_ridge), qh_qh(qh) {}
                         QhullRidge(QhullQh *qh, ridgeT *r) : qh_ridge(r ? r : &s_empty_ridge), qh_qh(qh) {}
                         // Creates an alias.  Does not copy QhullRidge.  Needed for return by value and parameter passing
                         QhullRidge(const QhullRidge &other) : qh_ridge(other.qh_ridge), qh_qh(other.qh_qh) {}
                         // Creates an alias.  Does not copy QhullRidge.  Needed for vector
     QhullRidge &        operator=(const QhullRidge &other) { qh_ridge= other.qh_ridge; qh_qh= other.qh_qh; return *this; }
                         ~QhullRidge() {}
 
 #//!\name GetSet
     QhullFacet          bottomFacet() const { return QhullFacet(qh_qh, qh_ridge->bottom); }
     int                 dimension() const { return qh_qh->hull_dim; }
     ridgeT *            getBaseT() const { return getRidgeT(); } //!< For QhullSet
     ridgeT *            getRidgeT() const { return qh_ridge; }
     countT              id() const { return qh_ridge->id; }
     bool                isDefined() const { return qh_ridge != &s_empty_ridge; }
     bool                operator==(const QhullRidge &other) const { return qh_ridge==other.qh_ridge; }
     bool                operator!=(const QhullRidge &other) const { return !operator==(other); }
     QhullFacet          otherFacet(const QhullFacet &f) const { return QhullFacet(qh_qh, (qh_ridge->top==f.getFacetT() ? qh_ridge->bottom : qh_ridge->top)); }
     QhullFacet          topFacet() const { return QhullFacet(qh_qh, qh_ridge->top); }
 
 #//!\name foreach
     bool                hasNextRidge3d(const QhullFacet &f) const;
     QhullRidge          nextRidge3d(const QhullFacet &f) const { return nextRidge3d(f, 0); }
     QhullRidge          nextRidge3d(const QhullFacet &f, QhullVertex *nextVertex) const;
     QhullVertexSet      vertices() const { return QhullVertexSet(qh_qh, qh_ridge->vertices); }
 
 #//!\name IO
 
     struct PrintRidge{
         const QhullRidge *ridge;
         const char *    print_message;
                         PrintRidge(const char *message, const QhullRidge &r) : ridge(&r), print_message(message) {}
     };//PrintRidge
     PrintRidge          print(const char* s) const { return PrintRidge(s, *this); }
 };//class QhullRidge
 
 }//namespace orgQhull
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullRidge &r); 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullRidge::PrintRidge &pr);
 
 #endif // QHULLRIDGE_H
diff --git a/src/libqhullcpp/QhullSet.cpp b/src/libqhullcpp/QhullSet.cpp
index b664838..1f3f3f9 100644
--- a/src/libqhullcpp/QhullSet.cpp
+++ b/src/libqhullcpp/QhullSet.cpp
@@ -1,61 +1,61 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullSet.cpp#10 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullSet.cpp#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullSet -- Qhull's set structure, setT, as a C++ class
 
 #include "Qhull.h"
 #include "QhullError.h"
 #include "QhullSet.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Class objects
 
 setT QhullSetBase::
 s_empty_set;
 
 #//!\name Constructors
 
 QhullSetBase::
 QhullSetBase(const Qhull &q, setT *s) 
 : qh_set(s ? s : &s_empty_set)
 , qh_qh(q.qh())
 {
 }
 
 #//!\name Class methods
 
 // Same code for qh_setsize [qset_r.c] and QhullSetBase::count [static]
 countT QhullSetBase::
 count(const setT *set)
 {
     countT size;
     const setelemT *sizep;
 
     if (!set){
         return(0);
     }
     sizep= SETsizeaddr_(set);
     if ((size= sizep->i)) {
         size--;
         if (size > set->maxsize) {
             // FIXUP QH11022 How to add additional output to a error? -- qh_setprint(qhmem.ferr, "set: ", set);
             throw QhullError(10032, "QhullSet internal error: current set size %d is greater than maximum size %d\n",
                 size, set->maxsize);
         }
     }else{
         size= set->maxsize;
     }
     return size;
 }//count
 
 }//namespace orgQhull
 
diff --git a/src/libqhullcpp/QhullSet.h b/src/libqhullcpp/QhullSet.h
index e6cee15..351db92 100644
--- a/src/libqhullcpp/QhullSet.h
+++ b/src/libqhullcpp/QhullSet.h
@@ -1,453 +1,453 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullSet.h#15 $$Change: 1801 $
-** $DateTime: 2014/12/17 22:37:12 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullSet.h#16 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QhullSet_H
 #define QhullSet_H
 
 #include "QhullError.h"
 #include "QhullQh.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 #ifdef QHULL_USES_QT
  #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Used here
     class Qhull;
 
 #//!\name Defined here
     class QhullSetBase;  //! Base class for QhullSet
     //! QhullSet defined below
     //! QhullSetIterator defined below
     //! \see QhullPointSet, QhullLinkedList
 
 //! QhullSetBase is a wrapper for Qhull's setT of void* pointers 
 //! \see libqhullr/qset.h
 class QhullSetBase {
 
 private:
 #//!\name Fields --
     setT *              qh_set;
     QhullQh *           qh_qh;             //! Provides access to setT memory allocator
 
 #//!\name Class objects
     static setT         s_empty_set;  //! Used if setT* is NULL
 
 public:
 #//!\name Constructors
                         QhullSetBase(const Qhull &q, setT *s);
                         QhullSetBase(QhullQh *qh, setT *s) : qh_set(s ? s : &s_empty_set), qh_qh(qh) {}
                         //! Copy constructor copies the pointer but not the set.  Needed for return by value and parameter passing.
                         QhullSetBase(const QhullSetBase &other) : qh_set(other.qh_set), qh_qh(other.qh_qh) {}
     QhullSetBase &      operator=(const QhullSetBase &other) { qh_set= other.qh_set; qh_qh= other.qh_qh; return *this; }
                         ~QhullSetBase() {}
 
 private:
                         //!disabled since memory allocation for QhullSet not defined
                         QhullSetBase() {}
 public:
 
 #//!\name GetSet
     countT              count() const { return QhullSetBase::count(qh_set); }
     void                defineAs(setT *s) { qh_set= s ? s : &s_empty_set; } //!< Not type-safe since setT may contain any type
     void                forceEmpty() { qh_set= &s_empty_set; }
     setT *              getSetT() const { return qh_set; }
     bool                isEmpty() const { return SETempty_(qh_set); }
     QhullQh *           qh() const { return qh_qh; }
     setT **             referenceSetT() { return &qh_set; }
     size_t              size() const { return QhullSetBase::count(qh_set); }
 
 #//!\name Element
 protected:
     void **             beginPointer() const { return &qh_set->e[0].p; }
     void **             elementPointer(countT idx) const { QHULL_ASSERT(idx>=0 && idxmaxsize); return &SETelem_(qh_set, idx); }
                         //! Always points to 0
     void **             endPointer() const { return qh_setendpointer(qh_set); }
 
 #//!\name Class methods
     static countT       count(const setT *set);
     //s may be null
     static bool         isEmpty(const setT *s) { return SETempty_(s); }
 };//QhullSetBase
 
 
 //! QhullSet -- A read-only wrapper to Qhull's collection class, setT.
 //!  QhullSet is similar to STL's  and Qt's QVector.
 //!  QhullSet is unrelated to STL and Qt's set and map types (e.g., QSet and QMap)
 //!  T is a Qhull type that defines 'base_type' and getBaseT() (e.g., QhullFacet with base_type 'facetT *'
 //!  A QhullSet does not own its contents -- erase(), clear(), removeFirst(), removeLast(), pop_back(), pop_front(), fromStdList() not defined
 //!  QhullSetIterator is faster than STL-style iterator/const_iterator
 //!  Qhull's FOREACHelement_() [qset_r.h] maybe more efficient than QhullSet.  It uses a NULL terminator instead of an end pointer.  STL requires an end pointer.
 //!  Derived from QhullLinkedList.h and Qt/core/tools/qvector.h
 template 
 class QhullSet : public QhullSetBase {
 
 private:
 #//!\name Fields -- see QhullSetBase
 
 #//!\name Class objects
     static setT         s_empty_set;  //! Workaround for no setT allocator.  Used if setT* is NULL
 
 public:
 #//!\name Defined here
     class iterator;
     class const_iterator;
     typedef typename QhullSet::iterator Iterator;
     typedef typename QhullSet::const_iterator ConstIterator;
 
 #//!\name Constructors
                         QhullSet(const Qhull &q, setT *s) : QhullSetBase(q, s) { }
                         QhullSet(QhullQh *qh, setT *s) : QhullSetBase(qh, s) { }
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                         //Copy constructor copies pointer but not contents.  Needed for return by value.
                         QhullSet(const QhullSet &other) : QhullSetBase(other) {}
     QhullSet &       operator=(const QhullSet &other) { QhullSetBase::operator=(other); return *this; }
                         ~QhullSet() {}
 
 private:
                         //!Disable default constructor.  See QhullSetBase
                         QhullSet();
 public:
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif
 #ifdef QHULL_USES_QT
     QList toQList() const;
 #endif
 
 #//!\name GetSet -- see QhullSetBase for count(), empty(), isEmpty(), size()
     using QhullSetBase::count;
     using QhullSetBase::isEmpty;
     // operator== defined for QhullSets of the same type
     bool                operator==(const QhullSet &other) const { return qh_setequal(getSetT(), other.getSetT()); }
     bool                operator!=(const QhullSet &other) const { return !operator==(other); }
 
 #//!\name Element access
     const T             at(countT idx) const { return operator[](idx); }
     T                   back() { return last(); }
     T                   back() const { return last(); }
     //! end element is NULL
     const typename typename T::base_type * constData() const { return reinterpret_cast(beginPointer()); }
     typename T::base_type *     data() { return reinterpret_cast(beginPointer()); }
     typename T::base_type *     data() const { return reinterpret_cast(beginPointer()); }
     typename T::base_type *     endData() { return reinterpret_cast(endPointer()); }
     typename T::base_type *     endData() const { return reinterpret_cast(endPointer()); }
     T                   first() { QHULL_ASSERT(!isEmpty()); return T(qh(), *data()); }
     const T             first() const { QHULL_ASSERT(!isEmpty()); return T(qh(), *data()); }
     T                   front() { return first(); }
     const T             front() const { return first(); }
     T                   last() { QHULL_ASSERT(!isEmpty()); return T(qh(), *(endData()-1)); }
     const T             last() const {  QHULL_ASSERT(!isEmpty()); return T(qh(), *(endData()-1)); }
     // mid() not available.  No setT constructor
     T                   operator[](countT idx) { typename T::base_type *p= reinterpret_cast(elementPointer(idx)); QHULL_ASSERT(idx>=0 && p < endData()); return T(qh(), *p); }
     const T             operator[](countT idx) const { const typename T::base_type *p= reinterpret_cast(elementPointer(idx)); QHULL_ASSERT(idx>=0 && p < endData()); return T(qh(), *p); }
     T                   second() { return operator[](1); }
     const T             second() const { return operator[](1); }
     T                   value(countT idx) const;
     T                   value(countT idx, const T &defaultValue) const;
 
 #//!\name Read-write -- Not available, no setT constructor
 
 #//!\name iterator
     iterator            begin() { return iterator(qh(), reinterpret_cast(beginPointer())); }
     const_iterator      begin() const { return const_iterator(qh(), data()); }
     const_iterator      constBegin() const { return const_iterator(qh(), data()); }
     const_iterator      constEnd() const { return const_iterator(qh(), endData()); }
     iterator            end() { return iterator(qh(), endData()); }
     const_iterator      end() const { return const_iterator(qh(), endData()); }
 
 #//!\name Search
     bool                contains(const T &t) const;
     countT              count(const T &t) const;
     countT              indexOf(const T &t) const { /* no qh_qh */ return qh_setindex(getSetT(), t.getBaseT()); }
     countT              lastIndexOf(const T &t) const;
 
     // before const_iterator for conversion with comparison operators
     class iterator {
         friend class const_iterator;
     private:
         typename T::base_type *  i;  // First for debugger
         QhullQh *       qh_qh;
 
     public:
         typedef ptrdiff_t       difference_type;
         typedef std::bidirectional_iterator_tag  iterator_category;
         typedef T               value_type;
 
                         iterator(QhullQh *qh, typename T::base_type *p) : i(p), qh_qh(qh) {}
                         iterator(const iterator &o) : i(o.i), qh_qh(o.qh_qh) {}
         iterator &      operator=(const iterator &o) { i= o.i; qh_qh= o.qh_qh; return *this; }
 
         T               operator*() const { return T(qh_qh, *i); }
         //operator->() n/a, value-type
         T               operator[](countT idx) { return T(qh_qh, *(i+idx)); } //!< No error checking
         bool            operator==(const iterator &o) const { return i == o.i; }
         bool            operator!=(const iterator &o) const { return !operator==(o); }
         bool            operator==(const const_iterator &o) const { return (i==reinterpret_cast(o).i); }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
 
         //! Assumes same point set
         countT          operator-(const iterator &o) { return (countT)(i-o.i); } //WARN64
         bool            operator>(const iterator &o) const { return i>o.i; }
         bool            operator<=(const iterator &o) const { return !operator>(o); }
         bool            operator<(const iterator &o) const { return i=(const iterator &o) const { return !operator<(o); }
         bool            operator>(const const_iterator &o) const { return (i > reinterpret_cast(o).i); }
         bool            operator<=(const const_iterator &o) const { return !operator>(o); }
         bool            operator<(const const_iterator &o) const { return (i < reinterpret_cast(o).i); }
         bool            operator>=(const const_iterator &o) const { return !operator<(o); }
 
         //! No error checking
         iterator &      operator++() { ++i; return *this; }
         iterator        operator++(int) { iterator o= *this; ++i; return o; }
         iterator &      operator--() { --i; return *this; }
         iterator        operator--(int) { iterator o= *this; --i; return o; }
         iterator        operator+(countT j) const { return iterator(qh_qh, i+j); }
         iterator        operator-(countT j) const { return operator+(-j); }
         iterator &      operator+=(countT j) { i += j; return *this; }
         iterator &      operator-=(countT j) { i -= j; return *this; }
     };//QhullPointSet::iterator
 
     class const_iterator {
     private:
         typename T::base_type *  i;  // First for debugger
         QhullQh *       qh_qh;
 
     public:
         typedef ptrdiff_t       difference_type;
         typedef std::random_access_iterator_tag  iterator_category;
         typedef T               value_type;
 
                         const_iterator(QhullQh *qh, typename T::base_type * p) : i(p), qh_qh(qh) {}
                         const_iterator(const const_iterator &o) : i(o.i), qh_qh(o.qh_qh) {}
                         const_iterator(const iterator &o) : i(o.i), qh_qh(o.qh_qh) {}
         const_iterator &operator=(const const_iterator &o) { i= o.i; qh_qh= o.qh_qh; return *this; }
 
         T               operator*() const { return T(qh_qh, *i); }
         T               operator[](countT idx) { return T(qh_qh, *(i+idx)); }  //!< No error checking
         //operator->() n/a, value-type
         bool            operator==(const const_iterator &o) const { return i == o.i; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
 
         //! Assumes same point set
         countT          operator-(const const_iterator &o) { return (countT)(i-o.i); } //WARN64
         bool            operator>(const const_iterator &o) const { return i>o.i; }
         bool            operator<=(const const_iterator &o) const { return !operator>(o); }
         bool            operator<(const const_iterator &o) const { return i=(const const_iterator &o) const { return !operator<(o); }
 
         //!< No error checking
         const_iterator &operator++() { ++i; return *this; }
         const_iterator  operator++(int) { const_iterator o= *this; ++i; return o; }
         const_iterator &operator--() { --i; return *this; }
         const_iterator  operator--(int) { const_iterator o= *this; --i; return o; }
         const_iterator  operator+(int j) const { return const_iterator(qh_qh, i+j); }
         const_iterator  operator-(int j) const { return operator+(-j); }
         const_iterator &operator+=(int j) { i += j; return *this; }
         const_iterator &operator-=(int j) { i -= j; return *this; }
     };//QhullPointSet::const_iterator
 
 };//class QhullSet
 
 
 //! Faster then interator/const_iterator due to T::base_type
 template 
 class QhullSetIterator {
 
 #//!\name Subtypes
     typedef typename QhullSet::const_iterator const_iterator;
 
 private:
 #//!\name Fields
     typename T::base_type *  i;  // First for debugger
     typename T::base_type *  begin_i;  // must be initialized after i 
     typename T::base_type *  end_i; 
     QhullQh *                qh_qh;
 
 public:
 #//!\name Constructors
                         QhullSetIterator(const QhullSet &s) : i(s.data()), begin_i(i), end_i(s.endData()), qh_qh(s.qh()) {}
                         QhullSetIterator(const QhullSetIterator &o) : i(o.i), begin_i(o.begin_i), end_i(o.end_i), qh_qh(o.qh_qh) {}
     QhullSetIterator &operator=(const QhullSetIterator &o) { i= o.i; begin_i= o.begin_i; end_i= o.end_i; qh_qh= o.qh_qh; return *this; }
 
 #//!\name ReadOnly
     countT              countRemaining() { return (countT)(end_i-i); } // WARN64
 
 #//!\name Search
     bool                findNext(const T &t);
     bool                findPrevious(const T &t);
 
 #//!\name Foreach
     bool                hasNext() const { return i != end_i; }
     bool                hasPrevious() const { return i != begin_i; }
     T                   next() { return T(qh_qh, *i++); }
     T                   peekNext() const { return T(qh_qh, *i); }
     T                   peekPrevious() const { typename T::base_type *p = i; return T(qh_qh, *--p); }
     T                   previous() { return T(qh_qh, *--i); }
     void                toBack() { i = end_i; }
     void                toFront() { i = begin_i; }
 };//class QhullSetIterator
 
 #//!\name == Definitions =========================================
 
 #//!\name Conversions
 
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 template 
 std::vector QhullSet::
 toStdVector() const
 {
     QhullSet::const_iterator i= begin();
     QhullSet::const_iterator e= end();
     std::vector vs;
     while(i!=e){
         vs.push_back(*i++);
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #ifdef QHULL_USES_QT
 template 
 QList QhullSet::
 toQList() const
 {
     QhullSet::const_iterator i= begin();
     QhullSet::const_iterator e= end();
     QList vs;
     while(i!=e){
         vs.append(*i++);
     }
     return vs;
 }//toQList
 #endif
 
 #//!\name Element
 
 template 
 T QhullSet::
 value(countT idx) const
 {
     // Avoid call to qh_setsize() and assert in elementPointer()
     const T::base_type *p= reinterpret_cast(&SETelem_(getSetT(), idx));
     return (idx>=0 && p
 T QhullSet::
 value(countT idx, const T &defaultValue) const
 {
     // Avoid call to qh_setsize() and assert in elementPointer()
     const typename T::base_type *p= reinterpret_cast(&SETelem_(getSetT(), idx));
     return (idx>=0 && p
 bool QhullSet::
 contains(const T &t) const
 {
     setT *s= getSetT();
     void *p= t.getBaseT();  // contains() is not inline for better error reporting
     int result= qh_setin(s, p);
     return result!=0;
 }//contains
 
 template 
 countT QhullSet::
 count(const T &t) const
 {
     countT n= 0;
     const typename T::base_type *i= data();
     const typename T::base_type *e= endData();
     typename T::base_type p= t.getBaseT();
     while(i
 countT QhullSet::
 lastIndexOf(const T &t) const
 {
     const typename T::base_type *b= data();
     const typename T::base_type *i= endData();
     typename T::base_type p= t.getBaseT();
     while(--i>=b){
         if(*i==p){
             break;
         }
     }
     return (countT)(i-b); // WARN64
 }//lastIndexOf
 
 #//!\name QhullSetIterator
 
 template 
 bool QhullSetIterator::
 findNext(const T &t)
 {
     typename T::base_type p= t.getBaseT();
     while(i!=end_i){
         if(*(++i)==p){
             return true;
         }
     }
     return false;
 }//findNext
 
 template 
 bool QhullSetIterator::
 findPrevious(const T &t)
 {
     typename T::base_type p= t.getBaseT();
     while(i!=begin_i){
         if(*(--i)==p){
             return true;
         }
     }
     return false;
 }//findPrevious
 
 }//namespace orgQhull
 
 
 #//!\name == Global namespace =========================================
 
 template 
 std::ostream &
 operator<<(std::ostream &os, const orgQhull::QhullSet &qs)
 {
     typename T::base_type *i= qs.data();
     typename T::base_type *e= qs.endData();
     while(i!=e){
         os << T(qs.qh(), *i++);
     }
     return os;
 }//operator<<
 
 #endif // QhullSet_H
diff --git a/src/libqhullcpp/QhullSets.h b/src/libqhullcpp/QhullSets.h
index 1f388e2..364a1c7 100644
--- a/src/libqhullcpp/QhullSets.h
+++ b/src/libqhullcpp/QhullSets.h
@@ -1,27 +1,27 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullSets.h#4 $$Change: 1707 $
-** $DateTime: 2014/03/26 09:42:11 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullSets.h#5 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLSETS_H
 #define QHULLSETS_H
 
 #include "QhullSet.h"
 
 namespace orgQhull {
 
     //See: QhullFacetSet.h
     //See: QhullPointSet.h
     //See: QhullVertexSet.h
 
     // Avoid circular references between QhullFacet, QhullRidge, and QhullVertex
     class QhullRidge;
     typedef QhullSet  QhullRidgeSet;
     typedef QhullSetIterator  QhullRidgeSetIterator;
 
 }//namespace orgQhull
 
 #endif // QHULLSETS_H
diff --git a/src/libqhullcpp/QhullStat.cpp b/src/libqhullcpp/QhullStat.cpp
index ef92145..27b502b 100644
--- a/src/libqhullcpp/QhullStat.cpp
+++ b/src/libqhullcpp/QhullStat.cpp
@@ -1,42 +1,42 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullStat.cpp#3 $$Change: 1464 $
-** $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullStat.cpp#5 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullStat -- Qhull's global data structure, statT, as a C++ class
 
 
 #include "QhullError.h"
 #include "QhullStat.h"
 
 #include 
 #include 
 
 using std::cerr;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Constructor, destructor, etc.
 
 //! If qh_QHpointer==0, invoke with placement new on qh_stat;
 QhullStat::
 QhullStat()
 {
 }//QhullStat
 
 QhullStat::
 ~QhullStat()
 {
 }//~QhullStat
 
 }//namespace orgQhull
 
diff --git a/src/libqhullcpp/QhullStat.h b/src/libqhullcpp/QhullStat.h
index 685adb3..f78c285 100644
--- a/src/libqhullcpp/QhullStat.h
+++ b/src/libqhullcpp/QhullStat.h
@@ -1,52 +1,52 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullStat.h#8 $$Change: 1707 $
-** $DateTime: 2014/03/26 09:42:11 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullStat.h#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLSTAT_H
 #define QHULLSTAT_H
 
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name defined here
     //! QhullStat -- Qhull's statistics, qhstatT, as a C++ class
     //! Statistics defined with zzdef_() control Qhull's behavior, summarize its result, and report precision problems.
     class QhullStat;
 
 class QhullStat : public qhstatT {
 
 private:
 #//!\name Fields (empty) -- POD type equivalent to qhstatT.  No data or virtual members
 
 public:
 #//!\name Constants
 
 #//!\name class methods
     static void         clearStatistics();
 
 #//!\name constructor, assignment, destructor, invariant
                         QhullStat();
                         ~QhullStat();
 
 private:
     //!disable copy constructor and assignment
                         QhullStat(const QhullStat &);
     QhullStat &         operator=(const QhullStat &);
 public:
 
 #//!\name Access
 };//class QhullStat
 
 }//namespace orgQhull
 
 #endif // QHULLSTAT_H
diff --git a/src/libqhullcpp/QhullVertex.cpp b/src/libqhullcpp/QhullVertex.cpp
index 88e02a0..c672373 100644
--- a/src/libqhullcpp/QhullVertex.cpp
+++ b/src/libqhullcpp/QhullVertex.cpp
@@ -1,106 +1,106 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullVertex.cpp#9 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullVertex.cpp#10 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullVertex -- Qhull's vertex structure, vertexT, as a C++ class
 
 #include "Qhull.h"
 #include "QhullPoint.h"
 #include "QhullFacetSet.h"
 #include "QhullVertex.h"
 #include "QhullFacet.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//!\name Class objects
 vertexT QhullVertex::
 s_empty_vertex= {0,0,0,0,0,
                  0,0,0,0,0,
                  0};
 
 #//!\name Constructors
 
 QhullVertex::QhullVertex(const Qhull &q)
 : qh_vertex(&s_empty_vertex)
 , qh_qh(q.qh())
 {
 }//Default
 
 QhullVertex::QhullVertex(const Qhull &q, vertexT *v)
 : qh_vertex(v ? v : &s_empty_vertex)
 , qh_qh(q.qh())
 {
 }//vertexT
 
 #//!\name foreach
 
 //! Return neighboring facets for a vertex
 //! If neither merging nor Voronoi diagram, requires Qhull::defineVertexNeighborFacets() beforehand.
 QhullFacetSet QhullVertex::
 neighborFacets() const
 {
     if(!neighborFacetsDefined()){
         throw QhullError(10034, "Qhull error: neighboring facets of vertex %d not defined.  Please call Qhull::defineVertexNeighborFacets() beforehand.", id());
     }
     return QhullFacetSet(qh_qh, qh_vertex->neighbors);
 }//neighborFacets
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 using std::string;
 using std::vector;
 using orgQhull::QhullPoint;
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetSet;
 using orgQhull::QhullFacetSetIterator;
 using orgQhull::QhullVertex;
 
 //! Duplicate of qh_printvertex [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullVertex::PrintVertex &pr)
 {
     QhullVertex v= *pr.vertex;
     QhullPoint p= v.point();
     os << "- p" << p.id() << " (v" << v.id() << "): ";
     const realT *c= p.coordinates();
     for(int k= p.dimension(); k--; ){
         os << " " << *c++; // FIXUP QH11010 %5.2g
     }
     if(v.getVertexT()->deleted){
         os << " deleted";
     }
     if(v.getVertexT()->delridge){
         os << " ridgedeleted";
     }
     os << endl;
     if(v.neighborFacetsDefined()){
         QhullFacetSetIterator i= v.neighborFacets();
         if(i.hasNext()){
             os << " neighborFacets:";
             countT count= 0;
             while(i.hasNext()){
                 if(++count % 100 == 0){
                     os << endl << "     ";
                 }
                 QhullFacet f= i.next();
                 os << " f" << f.id();
             }
             os << endl;
         }
     }
     return os;
 }//<< PrintVertex
 
diff --git a/src/libqhullcpp/QhullVertex.h b/src/libqhullcpp/QhullVertex.h
index 4a8117b..41ae776 100644
--- a/src/libqhullcpp/QhullVertex.h
+++ b/src/libqhullcpp/QhullVertex.h
@@ -1,105 +1,105 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullVertex.h#11 $$Change: 1800 $
-** $DateTime: 2014/12/17 21:46:45 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullVertex.h#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLVERTEX_H
 #define QHULLVERTEX_H
 
 #include "QhullPoint.h"
 #include "QhullLinkedList.h"
 #include "QhullSet.h"
 extern "C" {
     #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Used here
     class QhullFacetSet;
 
 #//!\name Defined here
     //! QhullVertex -- Qhull's vertex structure, vertexT [libqhull_r.h], as a C++ class
     class QhullVertex;
     typedef QhullLinkedList QhullVertexList;
     typedef QhullLinkedListIterator QhullVertexListIterator;
 
 
 /*********************
   topological information:
     next,previous       doubly-linked list of all vertices
     neighborFacets           set of adjacent facets (only if qh.VERTEXneighbors)
 
   geometric information:
     point               array of DIM coordinates
 */
 
 class QhullVertex {
 
 #//!\name Defined here
 public:
     typedef vertexT *   base_type;  // for QhullVertexSet
 
 private:
 #//!\name Fields
     vertexT *           qh_vertex;
     QhullQh *           qh_qh;
 
 #//!\name Class objects
     static vertexT      s_empty_vertex;  // needed for shallow copy
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
     explicit            QhullVertex(const Qhull &q);
                         QhullVertex(const Qhull &q, vertexT *v);
     explicit            QhullVertex(QhullQh *qh) : qh_vertex(&s_empty_vertex), qh_qh(qh) {}
                         QhullVertex(QhullQh *qh, vertexT *v) : qh_vertex(v ? v : &s_empty_vertex), qh_qh(qh) {}
                         // Creates an alias.  Does not copy QhullVertex.  Needed for return by value and parameter passing
                         QhullVertex(const QhullVertex &other) : qh_vertex(other.qh_vertex), qh_qh(other.qh_qh) {}
                         // Creates an alias.  Does not copy QhullVertex.  Needed for vector
     QhullVertex &       operator=(const QhullVertex &other) { qh_vertex= other.qh_vertex; qh_qh= other.qh_qh; return *this; }
                         ~QhullVertex() {}
 
 #//!\name GetSet
     int                 dimension() const { return qh_qh->hull_dim; }
     vertexT *           getBaseT() const { return getVertexT(); } //!< For QhullSet
     vertexT *           getVertexT() const { return qh_vertex; }
     countT              id() const { return qh_vertex->id; }
     bool                isDefined() const { return qh_vertex != &s_empty_vertex; }
                         //! True if defineVertexNeighborFacets() already called.  Auotomatically set for facet merging, Voronoi diagrams
     bool                neighborFacetsDefined() const { return qh_vertex->neighbors != 0; }
     QhullVertex         next() const { return QhullVertex(qh_qh, qh_vertex->next); }
     bool                operator==(const QhullVertex &other) const { return qh_vertex==other.qh_vertex; }
     bool                operator!=(const QhullVertex &other) const { return !operator==(other); }
     QhullPoint          point() const { return QhullPoint(qh_qh, qh_vertex->point); }
     QhullVertex         previous() const { return QhullVertex(qh_qh, qh_vertex->previous); }
     QhullQh *           qh() const { return qh_qh; }
 
 #//!\name foreach
     //See also QhullVertexList
     QhullFacetSet       neighborFacets() const;
 
 #//!\name IO
     struct PrintVertex{
         const QhullVertex *vertex;
         const char *    print_message;
                         PrintVertex(const char *message, const QhullVertex &v) : vertex(&v), print_message(message) {}
     };//PrintVertex
     PrintVertex         print(const char *message) const { return PrintVertex(message, *this); }
 };//class QhullVertex
 
 }//namespace orgQhull
 
 #//!\name GLobal
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertex::PrintVertex &pr);
 inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertex &v) { os << v.print(""); return os; }
 
 #endif // QHULLVERTEX_H
diff --git a/src/libqhullcpp/QhullVertexSet.cpp b/src/libqhullcpp/QhullVertexSet.cpp
index 5743bec..270c300 100644
--- a/src/libqhullcpp/QhullVertexSet.cpp
+++ b/src/libqhullcpp/QhullVertexSet.cpp
@@ -1,145 +1,145 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/QhullVertexSet.cpp#11 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/QhullVertexSet.cpp#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullVertexSet -- Qhull's linked Vertexs, as a C++ class
 
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 #include "QhullPoint.h"
 #include "QhullRidge.h"
 #include "QhullVertex.h"
 #include "Qhull.h"
 
 #include "UsingLibQhull.h"
 
 using std::string;
 using std::vector;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  /* interaction between '_setjmp' and C++ object destruction is non-portable */
                                     /* setjmp should not be implemented with 'catch' */
 #endif
 
 namespace orgQhull {
 
 QhullVertexSet::
 QhullVertexSet(const Qhull &q, facetT *facetlist, setT *facetset, bool allfacets)
 : QhullSet(q.qh(), 0)
 , qhsettemp_defined(false)
 {
     QH_TRY_(q.qh()){ // no object creation -- destructors skipped on longjmp()
         setT *vertices= qh_facetvertices(q.qh(), facetlist, facetset, allfacets);
         defineAs(vertices);
         qhsettemp_defined= true;
     }
     q.qh()->maybeThrowQhullMessage(QH_TRY_status);
 }//QhullVertexSet facetlist facetset
 
 QhullVertexSet::
 QhullVertexSet(QhullQh *qh, facetT *facetlist, setT *facetset, bool allfacets)
 : QhullSet(qh, 0)
 , qhsettemp_defined(false)
 {
     QH_TRY_(qh){ // no object creation -- destructors skipped on longjmp()
         setT *vertices= qh_facetvertices(qh, facetlist, facetset, allfacets);
         defineAs(vertices);
         qhsettemp_defined= true;
     }
     qh->maybeThrowQhullMessage(QH_TRY_status);
 }//QhullVertexSet facetlist facetset
 
 //! Copy constructor for argument passing and returning a result
 //! Only copies a pointer to the set.
 //! If qhsettemp_defined, transfers ownership to destination, otherwise the set will be freed twice
 //! If qhsettemp_defined and passed by value, the set will be empty on return to caller
 QhullVertexSet::
 QhullVertexSet(QhullVertexSet &other) 
 : QhullSet(other)
 , qhsettemp_defined(other.qhsettemp_defined)
 {
     other.qhsettemp_defined= false;
     other.forceEmpty();
 }//copy constructor
 
 //! Copy assignment only copies a pointer to the set.
 //! If qhsettemp_defined, transfers ownership to destination, otherwise the set will be freed twice
 //! If qhsettemp_defined and passed by value, the set will be empty on return to caller
 //! 'other' is not 'const' due to ownership transfer
 QhullVertexSet & QhullVertexSet::
 operator=(QhullVertexSet &other) 
 {
     QhullSet::operator=(other);
     qhsettemp_defined= other.qhsettemp_defined;
     other.qhsettemp_defined= false;
     other.forceEmpty();
     return *this;
 }//copy constructor
 
 void QhullVertexSet::
 freeQhSetTemp()
 {
     if(qhsettemp_defined){
         qhsettemp_defined= false;
         QH_TRY_(qh()){ // no object creation -- destructors skipped on longjmp()
             qh_settempfree(qh(), referenceSetT()); // errors if not top of tempstack or if qhmem corrupted
         }
         qh()->maybeThrowQhullMessage(QH_TRY_status, QhullError::NOthrow);
     }
 }//freeQhSetTemp
 
 QhullVertexSet::
 ~QhullVertexSet()
 {
     freeQhSetTemp();
 }//~QhullVertexSet
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::QhullVertex;
 using orgQhull::QhullVertexSet;
 using orgQhull::QhullVertexSetIterator;
 using orgQhull::UsingLibQhull;
 
 //! Print Vertex identifiers to stream.  Space prefix.  From qh_printVertexheader [io_r.c]
 ostream &
 operator<<(ostream &os, const QhullVertexSet::PrintIdentifiers &pr)
 {
     if(pr.print_message && *pr.print_message){
         os << pr.print_message;
     }
     for(QhullVertexSet::const_iterator i= pr.vertex_set->begin(); i!=pr.vertex_set->end(); ++i){
         const QhullVertex v= *i;
         os << " v" << v.id();
     }
     os << endl;
     return os;
 }//<
 
 namespace orgQhull {
 
 #//!\name Used here
     class QhullVertex;
 
 #//!\name Defined here
     //! QhullVertexSet -- a set of Qhull Vertices, as a C++ class.
     //! See Qhull
     class QhullVertexSet;
     typedef QhullSetIterator QhullVertexSetIterator;
 
 class QhullVertexSet : public QhullSet {
 
 private:
 #//!\name Fields
     bool                qhsettemp_defined;  //! Set was allocated with qh_settemp()
 
 public:
 #//!\name Constructor
                         QhullVertexSet(const Qhull &q, setT *s) : QhullSet(q, s), qhsettemp_defined(false) {}
                         QhullVertexSet(const Qhull &q, facetT *facetlist, setT *facetset, bool allfacets);
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                         QhullVertexSet(QhullQh *qh, setT *s) : QhullSet(qh, s), qhsettemp_defined(false) {}
                         QhullVertexSet(QhullQh *qh, facetT *facetlist, setT *facetset, bool allfacets);
                         //Copy constructor copies pointer but not contents.  Needed for return by value.
                         QhullVertexSet(QhullVertexSet &other);
     QhullVertexSet &    operator=(QhullVertexSet &other);
                         ~QhullVertexSet();
 
 private:
                         //!Default constructor disabled.  Will implement allocation later
                         QhullVertexSet();
 public:
 
 #//!\name Destructor
     void                freeQhSetTemp();
 
 #//!\name IO
     struct PrintVertexSet{
         const QhullVertexSet *vertex_set;
         const char *    print_message;
                         
                         PrintVertexSet(const char *message, const QhullVertexSet *s) : vertex_set(s), print_message(message) {}
     };//PrintVertexSet
     const PrintVertexSet print(const char *message) const { return PrintVertexSet(message, this); }
 
     struct PrintIdentifiers{
         const QhullVertexSet *vertex_set;
         const char *    print_message;
                         PrintIdentifiers(const char *message, const QhullVertexSet *s) : vertex_set(s), print_message(message) {}
     };//PrintIdentifiers
     PrintIdentifiers    printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }
 
 };//class QhullVertexSet
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet::PrintVertexSet &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet::PrintIdentifiers &p);
 inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet &vs) { os << vs.print(""); return os; }
 
 #endif // QHULLVERTEXSET_H
diff --git a/src/libqhullcpp/RboxPoints.cpp b/src/libqhullcpp/RboxPoints.cpp
index bba6877..897d137 100644
--- a/src/libqhullcpp/RboxPoints.cpp
+++ b/src/libqhullcpp/RboxPoints.cpp
@@ -1,221 +1,221 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/RboxPoints.cpp#9 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/RboxPoints.cpp#10 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullError.h"
 #include "RboxPoints.h"
 
 #include 
 
 using std::cerr;
 using std::endl;
 using std::istream;
 using std::ostream;
 using std::ostringstream;
 using std::string;
 using std::vector;
 using std::ws;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//! RboxPoints -- generate random PointCoordinates for qhull (rbox)
   
 
 #//!\name Constructors
 RboxPoints::
 RboxPoints()
 : PointCoordinates(0, "rbox")
 , rbox_new_count(0)
 , rbox_status(qh_ERRnone)
 , rbox_message()
 {
     allocateQhullQh();
 }
 
 //! Allocate and generate points according to rboxCommand
 //! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
 //! Same as appendPoints()
 RboxPoints::
 RboxPoints(const char *rboxCommand)
 : PointCoordinates(0, "rbox")
 , rbox_new_count(0)
 , rbox_status(qh_ERRnone)
 , rbox_message()
 {
     allocateQhullQh();
     appendPoints(rboxCommand);
 }
 
 RboxPoints::
 ~RboxPoints()
 {
     delete qh();
     setQhullQh(0);
 }
 
 // RboxPoints and qh_rboxpoints has several fields in qhT (rbox_errexit..cpp_object)
 // It shares last_random with qh_rand and qh_srand
 // The other fields are unused
 void RboxPoints::
 allocateQhullQh()
 {
     setQhullQh(new QhullQh);
 }//allocateQhullQh
 
 #//!\name Messaging
 
 void RboxPoints::
 clearRboxMessage()
 {
     rbox_status= qh_ERRnone;
     rbox_message.clear();
 }//clearRboxMessage
 
 std::string RboxPoints::
 rboxMessage() const
 {
     if(rbox_status!=qh_ERRnone){
         return rbox_message;
     }
     if(isEmpty()){
         return "rbox warning: no points generated\n";
     }
     return "rbox: OK\n";
 }//rboxMessage
 
 int RboxPoints::
 rboxStatus() const
 {
     return rbox_status;
 }
 
 bool RboxPoints::
 hasRboxMessage() const
 {
     return (rbox_status!=qh_ERRnone);
 }
 
 #//!\name Methods
 
 //! Appends points as defined by rboxCommand
 //! Appends rboxCommand to comment
 //! For rbox commands, see http://www.qhull.org/html/rbox.htm or html/rbox.htm
 void RboxPoints::
 appendPoints(const char *rboxCommand)
 {
     string s("rbox ");
     s += rboxCommand;
     char *command= const_cast(s.c_str());
     if(qh()->cpp_object){
         throw QhullError(10001, "Qhull error: conflicting user of cpp_object for RboxPoints::appendPoints() or corrupted qh_qh");
     }
     if(extraCoordinatesCount()!=0){
         throw QhullError(10067, "Qhull error: Extra coordinates (%d) prior to calling RboxPoints::appendPoints.  Was %s", extraCoordinatesCount(), 0, 0.0, comment().c_str());
     }
     countT previousCount= count();
     qh()->cpp_object= this;           // for qh_fprintf_rbox()
     int status= qh_rboxpoints(qh(), command);
     qh()->cpp_object= 0;         
     if(rbox_status==qh_ERRnone){
         rbox_status= status;
     }
     if(rbox_status!=qh_ERRnone){
         throw QhullError(rbox_status, rbox_message);
     }
     if(extraCoordinatesCount()!=0){
         throw QhullError(10002, "Qhull error: extra coordinates (%d) for PointCoordinates (%x)", extraCoordinatesCount(), 0, 0.0, coordinates());
     }
     if(previousCount+newCount()!=count()){
         throw QhullError(10068, "Qhull error: rbox specified %d points but got %d points for command '%s'", newCount(), count()-previousCount, 0.0, comment().c_str());
     }
 }//appendPoints
 
 }//namespace orgQhull
 
 #//!\name Global functions
 
 /*---------------------------------
 
   qh_fprintf_rbox(qh, fp, msgcode, format, list of args )
     fp is ignored (replaces qh_fprintf_rbox() in userprintf_rbox.c)
     cpp_object == RboxPoints
 
 notes:
     only called from qh_rboxpoints()
     same as fprintf() and Qhull.qh_fprintf()
     fgets() is not trapped like fprintf()
     Do not throw errors from here.  Use qh_errexit_rbox;
     A similar technique can be used for qh_fprintf to capture all of its output
 */
 extern "C"
 void qh_fprintf_rbox(qhT *qh, FILE*, int msgcode, const char *fmt, ... ) {
     va_list args;
 
     using namespace orgQhull;
 
     if(!qh->cpp_object){
         qh_errexit_rbox(qh, 10072);
     }
     RboxPoints *out= reinterpret_cast(qh->cpp_object);
     va_start(args, fmt);
     if(msgcoderbox_message += newMessage;
         if(out->rbox_statusrbox_status>=MSG_STDERR){
             out->rbox_status= msgcode;
         }
         va_end(args);
         return;
     }
     switch(msgcode){
     case 9391:
     case 9392:
         out->rbox_message += "RboxPoints error: options 'h', 'n' not supported.\n";
         qh_errexit_rbox(qh, 10010);
         /* never returns */
     case 9393:  // FIXUP countT vs. int
         {
             int dimension= va_arg(args, int);
             string command(va_arg(args, char*));
             countT count= va_arg(args, countT);
             out->setDimension(dimension);
             out->appendComment(" \"");
             out->appendComment(command.substr(command.find(' ')+1));
             out->appendComment("\"");
             out->setNewCount(count);
             out->reservePoints();
         }
         break;
     case 9407:
         *out << va_arg(args, int);
         // fall through
     case 9405:
         *out << va_arg(args, int);
         // fall through
     case 9403:
         *out << va_arg(args, int);
         break;
     case 9408:
         *out << va_arg(args, double);
         // fall through
     case 9406:
         *out << va_arg(args, double);
         // fall through
     case 9404:
         *out << va_arg(args, double);
         break;
     }
     va_end(args);
 } /* qh_fprintf_rbox */
 
diff --git a/src/libqhullcpp/RboxPoints.h b/src/libqhullcpp/RboxPoints.h
index f9e376e..7f01229 100644
--- a/src/libqhullcpp/RboxPoints.h
+++ b/src/libqhullcpp/RboxPoints.h
@@ -1,71 +1,71 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/RboxPoints.h#11 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/RboxPoints.h#12 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef RBOXPOINTS_H
 #define RBOXPOINTS_H
 
 #include "QhullPoint.h"
 #include "PointCoordinates.h"
 extern "C" {
 #include "libqhullr/qhull_ra.h"
 }
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! RboxPoints -- generate random PointCoordinates for Qhull
     class RboxPoints;
 
 class RboxPoints : public PointCoordinates {
 
 private:
 #//!\name Fields and friends
-                        //! qh() is owned by RboxPoints 
+                        //! PointCoordinates.qh() is owned by RboxPoints 
     countT              rbox_new_count;     //! Number of points for PointCoordinates
     int                 rbox_status;    //! error status from rboxpoints.  qh_ERRnone if none.
     std::string         rbox_message;   //! stderr from rboxpoints
  
     // '::' is required for friend references
     friend void ::qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
 
 public:
 #//!\name Construct
                         RboxPoints();
     explicit            RboxPoints(const char *rboxCommand);
                         ~RboxPoints();
 private:                // Disable copy constructor and assignment.  RboxPoints owns QhullQh.
                         RboxPoints(const RboxPoints &);
                         RboxPoints &operator=(const RboxPoints &);
 private:
     void                allocateQhullQh();
 
 public:
 #//!\name GetSet
     void                clearRboxMessage();
     countT              newCount() const { return rbox_new_count; }
     std::string         rboxMessage() const;
     int                 rboxStatus() const;
     bool                hasRboxMessage() const;
     void                setNewCount(countT pointCount) { QHULL_ASSERT(pointCount>=0); rbox_new_count= pointCount; }
 
 #//!\name Modify
     void                appendPoints(const char* rboxCommand);
     using               PointCoordinates::appendPoints;
     void                reservePoints() { reserveCoordinates((count()+newCount())*dimension()); }
 };//class RboxPoints
 
 }//namespace orgQhull
 
 #endif // RBOXPOINTS_H
diff --git a/src/libqhullcpp/RoadError.cpp b/src/libqhullcpp/RoadError.cpp
index 901e83a..e87c428 100644
--- a/src/libqhullcpp/RoadError.cpp
+++ b/src/libqhullcpp/RoadError.cpp
@@ -1,156 +1,156 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/RoadError.cpp#1 $$Change: 1490 $
-** $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/RoadError.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! RoadError -- All exceptions thrown by Qhull are RoadErrors
 #//! Do not throw RoadError's from destructors.  Use e.logError() instead.
 
 #include "RoadError.h"
 
 #include 
 #include 
 #include 
 
 using std::cerr;
 using std::cout;
 using std::string;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Class fields
 
 //! Identifies error messages from Qhull and Road for web searches.
 //! See QhullError.h#QHULLlastError and user.h#MSG_ERROR
 const char * RoadError::
 ROADtag= "QH";
 
 std::ostringstream RoadError::
 global_log;
 
 #//Constructor
 
 RoadError::
 RoadError()
 : error_code(0)
 , log_event()
 , error_message()
 { }
 
 RoadError::
 RoadError(const RoadError &other)
 : error_code(other.error_code)
 , log_event(other.log_event)
 , error_message(other.error_message)
 {
 }//copy construct
 
 RoadError::
 RoadError(int code, const std::string &message)
 : error_code(code)
 , log_event(message.c_str())
 , error_message(log_event.toString(ROADtag, error_code))
 {
     log_event.cstr_1= error_message.c_str(); // overwrites initial value
 }
 
 RoadError::
 RoadError(int code, const char *fmt)
 : error_code(code)
 , log_event(fmt)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d)
 : error_code(code)
 , log_event(fmt, d)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2)
 : error_code(code)
 , log_event(fmt, d, d2)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f)
 : error_code(code)
 , log_event(fmt, d, d2, f)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, const char *s)
 : error_code(code)
 , log_event(fmt, d, d2, f, s)
 , error_message(log_event.toString(ROADtag, code)) // char * may go out of scope
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, const void *x)
 : error_code(code)
 , log_event(fmt, d, d2, f, x)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, int i)
 : error_code(code)
 , log_event(fmt, d, d2, f, i)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, long long i)
 : error_code(code)
 , log_event(fmt, d, d2, f, i)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, double e)
 : error_code(code)
 , log_event(fmt, d, d2, f, e)
 , error_message()
 { }
 
 RoadError & RoadError::
 operator=(const RoadError &other)
 {
     error_code= other.error_code;
     error_message= other.error_message;
     log_event= other.log_event;
     return *this;
 }//operator=
 
 #//Virtual
 const char * RoadError::
 what() const throw()
 {
     if(error_message.empty()){
         error_message= log_event.toString(ROADtag, error_code);
     }
     return error_message.c_str();
 }//what
 
 #//Updates
 
 //! Log error instead of throwing it.
 void RoadError::
 logError() const
 {
     global_log << what() << endl;
 }//logError
 
 
 }//namespace orgQhull
 
diff --git a/src/libqhullcpp/RoadError.h b/src/libqhullcpp/RoadError.h
index b20921e..7fbc260 100644
--- a/src/libqhullcpp/RoadError.h
+++ b/src/libqhullcpp/RoadError.h
@@ -1,86 +1,86 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/RoadError.h#4 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/RoadError.h#5 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef ROADERROR_H
 #define ROADERROR_H
 
 #include "RoadLogEvent.h"
 
 #include 
 #include 
 #include 
 #include 
 
 using std::endl;
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! RoadError -- Report and log errors
     //!  See discussion in Saylan, G., "Practical C++ error handling in hybrid environments," Dr. Dobb's Journal, p. 50-55, March 2007.
     //!   He uses an auto_ptr to track a stringstream.  It constructs a string on the fly.  RoadError uses the copy constructor to transform RoadLogEvent into a string
     class RoadError;
 
 class RoadError : public std::exception {
 
 private:
 #//!\name Fields
     int                 error_code;  //! Non-zero code (not logged), maybe returned as program status
     RoadLogEvent        log_event;   //! Format string w/ arguments
     mutable std::string error_message;  //! Formated error message.  Must be after log_event.
 
 #//!\name Class fields
     static const char  *  ROADtag;
     static std::ostringstream  global_log; //! May be replaced with any ostream object
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
     RoadError();
     RoadError(const RoadError &other);  //! Called on throw, generates error_message
     RoadError(int code, const std::string &message);
     RoadError(int code, const char *fmt);
     RoadError(int code, const char *fmt, int d);
     RoadError(int code, const char *fmt, int d, int d2);
     RoadError(int code, const char *fmt, int d, int d2, float f);
     RoadError(int code, const char *fmt, int d, int d2, float f, const char *s);
     RoadError(int code, const char *fmt, int d, int d2, float f, const void *x);
     RoadError(int code, const char *fmt, int d, int d2, float f, int i);
     RoadError(int code, const char *fmt, int d, int d2, float f, long long i);
     RoadError(int code, const char *fmt, int d, int d2, float f, double e);
 
     RoadError &         operator=(const RoadError &other);
                         ~RoadError() throw() {};
 
 #//!\name Class methods
 
     static void         clearGlobalLog() { global_log.seekp(0); }
     static bool         emptyGlobalLog() { return global_log.tellp()<=0; }
     static const char  *stringGlobalLog() { return global_log.str().c_str(); }
 
 #//!\name Virtual
     virtual const char *what() const throw();
 
 #//!\name GetSet
     bool                isDefined() const { return log_event.isDefined(); }
     int                 errorCode() const { return error_code; };
    // FIXUP QH11021 should RoadError provide errorMessage().  Currently what()
     RoadLogEvent        roadLogEvent() const { return log_event; };
 
 #//!\name Update
     void                logError() const;
 };//class RoadError
 
 }//namespace orgQhull
 
 #//!\name Global
 
 inline std::ostream &   operator<<(std::ostream &os, const orgQhull::RoadError &e) { return os << e.what(); }
 
 #endif // ROADERROR_H
diff --git a/src/libqhullcpp/RoadLogEvent.cpp b/src/libqhullcpp/RoadLogEvent.cpp
index d1abb33..b680498 100644
--- a/src/libqhullcpp/RoadLogEvent.cpp
+++ b/src/libqhullcpp/RoadLogEvent.cpp
@@ -1,122 +1,122 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/RoadLogEvent.cpp#1 $$Change: 1490 $
-** $Date: 2012/02/19 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/RoadLogEvent.cpp#3 $$Change: 1810 $
+** $Date: 2015/01/17 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! RoadError -- All exceptions thrown by Qhull are RoadErrors
 
 #include "RoadError.h"
 
 #include 
 #include 
 #include 
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::string;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Conversion
 string RoadLogEvent::
 toString(const char *tag, int code) const
 {
     ostringstream os;
     if(tag && code){
         os << tag << code;
         if(format_string){
             os << " ";
         }
     }
     if(!format_string){
         return os.str();
     }
     const char *s= format_string;
     int dCount= 0;  // Count of %d
     int fCount= 0;  // Count of %f
     char extraCode= '\0';
     while(*s){
         if(*s!='%'){
             os << *s++;
         }else{
             char c= *++s;
             s++;
             switch(c){
             case 'd':
                 if(++dCount>2){
                     os << " ERROR_three_%d_in_format ";
                 }else if(dCount==2){
                     os << int_2;
                 }else{
                     os << int_1;
                 }
                 break;
             case 'e':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << double_1;
                 }
                 break;
             case 'f':
                 if(++fCount>1){
                     os << " ERROR_two_%f_in_format ";
                 }else{
                     os << float_1;
                 }
                 break;
             case 'i':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << int64_1;
                 }
                 break;
             case 's':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << cstr_1;
                 }
                 break;
             case 'u':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << "0x" << std::hex << int64_1 << std::dec;
                 }
                 break;
             case 'x':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << void_1;
                 }
                 break;
             case '%':
                 os << c;
                 break;
             default:
                 os << " ERROR_%" << c << "_not_defined_in_format";
                 break;
             }
         }
     }
     if(s[-1]!='\n'){
         os << endl;
     }
     return os.str();
 }//toString
 
 #//Class helpers (static)
 
 //! True if this char is the first extra code
 bool RoadLogEvent::
 firstExtraCode(std::ostream &os, char c, char *extraCode){
     if(*extraCode){
         os << " ERROR_%" << *extraCode << "_and_%" << c << "_in_format ";
         return false;
     }
     *extraCode= c;
     return true;
 }//firstExtraCode
 
 }//namespace orgQhull
 
diff --git a/src/libqhullcpp/RoadLogEvent.h b/src/libqhullcpp/RoadLogEvent.h
index 722d6e5..caf57e2 100644
--- a/src/libqhullcpp/RoadLogEvent.h
+++ b/src/libqhullcpp/RoadLogEvent.h
@@ -1,77 +1,77 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/RoadLogEvent.h#4 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/RoadLogEvent.h#5 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef ROADLOGEVENT_H
 #define ROADLOGEVENT_H
 
 #include 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! RoadLogEvent -- Record an event for the RoadLog
     struct RoadLogEvent;
 
 struct RoadLogEvent {
 
 public:
 #//!\name Fields
     const char *    format_string; //! Format string (a literal with format codes, for logging)
     int             int_1;       //! Integer argument (%d, for logging)
     int             int_2;       //! Integer argument (%d, for logging)
     float           float_1;     //! Float argument (%f, for logging)
     union {                      //! One additional argument (for logging)
         const char *cstr_1;      //!   Cstr argument (%s) -- type checked at construct-time
         const void *void_1;      //!   Void* argument (%x) -- Use upper-case codes for object types
         long long   int64_1;     //!   signed int64 (%i).  Ambiguous if unsigned is also defined.
         double      double_1;    //!   Double argument (%e)
     };
 
 #//!\name Constants
 
 #//!\name Constructors
     RoadLogEvent() : format_string(0), int_1(0), int_2(0), float_1(0), int64_1(0) {};
     explicit RoadLogEvent(const char *fmt) : format_string(fmt), int_1(0), int_2(0), float_1(0), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d) : format_string(fmt), int_1(d), int_2(0), float_1(0), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d, int d2) : format_string(fmt), int_1(d), int_2(d2), float_1(0), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, const char *s) : format_string(fmt), int_1(d), int_2(d2), float_1(f), cstr_1(s) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, const void *x) : format_string(fmt), int_1(d), int_2(d2), float_1(f), void_1(x) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, int i) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(i) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, long long i) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(i) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, double g) : format_string(fmt), int_1(d), int_2(d2), float_1(f), double_1(g) {};
     ~RoadLogEvent() {};
     //! Default copy constructor and assignment
 
 #//!\name GetSet
     bool                isDefined() const { return format_string!=0; }
     int                 int1() const { return int_1; };
     int                 int2() const { return int_2; };
     float               float1() const { return float_1; };
     const char *        format() const { return format_string; };
     const char *        cstr1() const { return cstr_1; };
     const void *        void1() const { return void_1; };
     long long           int64() const { return int64_1; };
     double              double1() const { return double_1; };
 
 #//!\name Conversion
 
     std::string        toString(const char* tag, int code) const;
 
 private:
 #//!\name Class helpers
     static bool         firstExtraCode(std::ostream &os, char c, char *extraCode);
 
 
 };//class RoadLogEvent
 
 }//namespace orgQhull
 
 #endif // ROADLOGEVENT_H
diff --git a/src/libqhullcpp/UsingLibQhull.cpp b/src/libqhullcpp/UsingLibQhull.cpp
index 7c0ead0..d367eaf 100644
--- a/src/libqhullcpp/UsingLibQhull.cpp
+++ b/src/libqhullcpp/UsingLibQhull.cpp
@@ -1,179 +1,179 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/UsingLibQhull.cpp#7 $$Change: 1708 $
-** $DateTime: 2014/03/26 19:13:56 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/UsingLibQhull.cpp#8 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! UsingLibQhull -- Set up qhull C code from C++
 
 #include "Qhull.h"
 #include "UsingLibQhull.h"
 #include "QhullError.h"
 #include "QhullQh.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Class objects
 
 const double UsingLibQhull::
 DEFAULTdistanceEpsilon= 1e-15*FACTORepsilon; //! ~DISTround*FACTORepsilon for unit cube
 
 const double UsingLibQhull::
 DEFAULTangleEpsilon= 1e-15*FACTORepsilon; //! ~ANGLEround*FACTORepsilon for unit cube
 
     //! Global pointer to Qhull for qh_fprintf callback and QhullError
 Qhull *
 s_qhull_output= 0;
 
 double UsingLibQhull::
 s_angle_epsilon= 0;
 
 double UsingLibQhull::
 s_distance_epsilon= 0;
 
 //! For QhullPoint.id() w/o qhRunId.  Initialized by Qhull
 const coordT *UsingLibQhull::
 s_points_begin= 0;
 const coordT *UsingLibQhull::
 s_points_end= 0;
 int UsingLibQhull::
 s_points_dimension= 0;
 
 int UsingLibQhull::
 s_vertex_dimension= 0;  // FIXUP QH11023: s_vertex_dimension is required if dimension>15.  Cannot store in QhullVertex
 
 bool UsingLibQhull::
 s_has_points= false;
 
 bool UsingLibQhull::
 s_has_angle_epsilon= false;
 
 bool UsingLibQhull::
 s_has_vertex_dimension= false;
 
 bool UsingLibQhull::
 s_has_distance_epsilon= false;
 
 bool UsingLibQhull::
 s_using_libqhull= false;
 
 #//Constructors
 
 //! Grabs global state (qh_qh, qh_qhstat, qhmem.tempstack)
 //! Follow immediately with setjmp(qh->errexit), otherwise errors in libqhull are not caught properly
 //! See qh_restore_qhull [global.c]
 UsingLibQhull::
 UsingLibQhull(Qhull *q)
 : my_qhull(q)
 , qh_exitcode(0)
 {
     checkUsingLibQhull();
     QhullQh *qhullqh= q->qhullQh();
     if(!qhullqh){
         throw QhullError(10014, "Qhull internal error: Qhull.qhullQh() not defined. initializeQhull() not called.");
     }
     s_qhull_output= q;      // set s_qhull_output for qh_fprintf()
     qh->NOerrexit= False;   // assumes setjmp called next
 }//UsingLibQhull qhull
 
 //! Same as UsingLibQhull but does not throw exceptions
 //! !defined() on failure.  For use in destructors
 UsingLibQhull::
 UsingLibQhull(Qhull *q, int noThrow)
 : my_qhull(0)  // Fail by default
 , qh_exitcode(0)
 {
     QHULL_UNUSED(noThrow);
 
     QhullQh *qhullqh= q->qhullQh();
         my_qhull= q;
         s_qhull_output= q;          // set s_qhull_output for qh_fprintf()
         qh NOerrexit= False;   // assumes setjmp called next
     }
 }//UsingLibQhull qhull noThrow
 
 //! Reuses current global state (qh_qh) from prior UsingQhull
 //! Errors if runId is not the same
 UsingLibQhull::
 UsingLibQhull(int qhRunId)
 : my_qhull(0)
 , qh_exitcode(0)
 {
     checkUsingLibQhull();
 #if qh_QHpointer
     if(!qh_qh || !qh_qhstat){
         throw QhullError(10024, "Qhull error: UsingLibQhull is not active (qh_qh %x or qh_qhstat is not defined)", 0,0,0.0, qh_qh);
     }
 #endif
     if(qh run_id!=qhRunId){
         throw QhullError(10036, "Qhull error: qhRunId %d != qh_qh.runId %d.  Is another Qhull active?", qhRunId, qh run_id);
     }
     if(!s_qhull_output){
         throw QhullError(10037, "Qhull error: UsingLibQhull not active(s_qhull_output undefined).  Invoke UsingLibQhull before this call");
     }
     if(s_qhull_output->qhull_run_id!=qhRunId){
         throw QhullError(10046, "Qhull error: qhRunId %d != s_qhull_output.runId %d.  Is another Qhull active", qhRunId, s_qhull_output->qhull_run_id);
     }
     my_qhull= s_qhull_output;
     qh NOerrexit= False;   // assumes setjmp called next
 }//UsingLibQhull runId
 
 //Leaves libqhull active for runId access
 UsingLibQhull::
 ~UsingLibQhull()
 {
     QhullError e= checkRunId();
     if(e.isDefined()){
         e.logError();
     }else{
 #if qh_QHpointer
         if(qh_qh){
             qh NOerrexit= true;
         }
 #else
         qh NOerrexit= true;
 #endif
     }
     s_using_libqhull= false;
 }//~UsingLibQhull
 
 #//Class methods
 
 void UsingLibQhull::
 setGlobals()
 {
     if(s_qhull_output && s_qhull_output->initialized()){
         QhullQh *qqh= s_qhull_output->qhullQh();
         s_angle_epsilon= qqh->ANGLEround*FACTORepsilon;
         s_distance_epsilon= qqh->DISTround*FACTORepsilon;
         s_points_begin= qqh->first_point;
         s_points_dimension= qqh->hull_dim;
         s_points_end= s_points_begin+qqh->num_points*s_points_dimension;
         s_vertex_dimension= qqh->hull_dim;
         s_has_angle_epsilon= true;
         s_has_distance_epsilon= true;
         s_has_points= true;
         s_has_vertex_dimension= true;
     }else{
         throw QhullError(10058, "Qhull error: setGlobals can only be called for currentQhull().  Run qhull first.");
     }
  }//setGlobals
 
 void UsingLibQhull::
 unsetGlobals()
 {
     s_has_angle_epsilon= false;
     s_has_distance_epsilon= false;
     s_has_points= false;
     s_has_vertex_dimension= false;
 }//unsetGlobals
 
 #//Helpers
 
 }//namespace orgQhull
 
diff --git a/src/libqhullcpp/UsingLibQhull.h b/src/libqhullcpp/UsingLibQhull.h
index fb3663d..538cc48 100644
--- a/src/libqhullcpp/UsingLibQhull.h
+++ b/src/libqhullcpp/UsingLibQhull.h
@@ -1,141 +1,141 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/UsingLibQhull.h#8 $$Change: 1707 $
-** $DateTime: 2014/03/26 09:42:11 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/UsingLibQhull.h#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef USINGlibqhull_H
 #define USINGlibqhull_H
 
 #include "QhullError.h"
 extern "C" {
 #include "libqhullr/qhull_ra.h"
 }
 
 namespace orgQhull {
 
 #//!\name Types
     //! UsingLibQhull -- Interface into libqhull and its 'qh' and 'qhstat' macros
     //! Always use with setjmp() for libqhull error handling.
 
 /*******************************
 
 UsingLibQhull is stack based, but as a call
 Qhull declarations are stack-based.  But can't define a
 setjmp environment, since the target goes away.  So must be UsingLibQhull, but can only have one
 setjmp at a time? Can embedded another Using as long as save/restore
 longjmp on exit.
 */
     class UsingLibQhull;
 
     // Defined elsewhere
     class Qhull;
 
 class UsingLibQhull {
 
 private:
 #//!\name Fields
     Qhull *             my_qhull;
     int                 qh_exitcode;
 
 #//!\name Class globals
     //! Global flags
     static bool         s_using_libqhull; //! True if UsingLibQhull is in scope
 
     //! Use global values if s_has_... is set
     static bool         s_has_angle_epsilon; //! True if s_angle_epsilon defined
     static bool         s_has_distance_epsilon; //! True if s_distance_epsilon defined
     static bool         s_has_points;        //! If False (default), Qhull() runs setPointBase()
     static bool         s_has_vertex_dimension; //! True if s_vertex_dimension defined
 
     //! Global values
     static double       s_angle_epsilon;   //! Epsilon for angle equality
     static double       s_distance_epsilon;   //! Epsilon for distance equality
     static const coordT *s_points_begin;            //! For QhullPoint::id() w/o qhRunId.
     static const coordT *s_points_end;            //! For QhullPoint::id() w/o qhRunId.
     static int          s_points_dimension;
     static int          s_vertex_dimension; //! Default dimension (e.g., if Vertex::dimension() >= 16)
 
 public:
 #//!\name Class constants
     static const int    NOqhRunId= 0;   //! qh_qh is not available
     static const int    NOthrow= 1;     //! Do not throw from maybeThrowQhullMessage
     static const int    FACTORepsilon= 10;  //!
     static const double DEFAULTdistanceEpsilon; //! ~DISTround*FACTORepsilon for unit cube
     static const double DEFAULTangleEpsilon;    //! ~ANGLEround*FACTORepsilon for unit cube
 
 #//!\name Class members
     static void         checkQhullMemoryEmpty();
     static double       currentAngleEpsilon();
     static double       currentDistanceEpsilon();
     static const coordT *currentPoints(int *dimension, const coordT **pointsEnd);
     static Qhull &      currentQhull();
     static int          currentVertexDimension();
     static double       globalAngleEpsilon() { return s_has_angle_epsilon ? s_angle_epsilon : currentAngleEpsilon(); }
     static double       globalDistanceEpsilon() { return s_has_distance_epsilon ? s_distance_epsilon : currentDistanceEpsilon(); }
     static double       globalMachineEpsilon() { return REALepsilon; }
     static const coordT *globalPoints(int *dimension, const coordT **pointsEnd);
     static int          globalVertexDimension() { return s_has_vertex_dimension ? s_vertex_dimension : currentVertexDimension(); }
     static bool         hasPoints();        // inline would require Qhull.h
     static bool         hasVertexDimension();
     static void         setGlobalAngleEpsilon(double d) { s_angle_epsilon=d; s_has_angle_epsilon= true; }
     static void         setGlobalDistanceEpsilon(double d) { s_distance_epsilon= d; s_has_distance_epsilon= true; }
     static void         setGlobalPoints(int dimension, const coordT *pointsBegin, const coordT *pointsEnd) { s_points_dimension= dimension; s_points_begin= pointsBegin; s_points_end= pointsEnd; s_has_points= true; }
     static void         setGlobalVertexDimension(int i) { s_vertex_dimension= i; s_has_vertex_dimension= true; }
     static void         setGlobals();
     static void         unsetGlobalAngleEpsilon() { s_has_angle_epsilon= false; }
     static void         unsetGlobalDistanceEpsilon() { s_has_distance_epsilon= false; }
     static void         unsetGlobalPoints() { s_has_points= false; }
     static void         unsetGlobalVertexDimension() { s_has_vertex_dimension= false; }
     static void         unsetGlobals();
 
 #//!\name Constructors
                         UsingLibQhull(Qhull *p);
                         UsingLibQhull(Qhull *p, int noThrow);
                         UsingLibQhull(int qhRunId);
                         ~UsingLibQhull();
 
 private:                //! disable default constructor, copy constructor, and copy assignment
                         UsingLibQhull();
                         UsingLibQhull(const UsingLibQhull &);
    UsingLibQhull &      operator=(const UsingLibQhull &);
 public:
 
 #//!\name Methods
 #//!\name Access
     bool                defined() const { return my_qhull!=0; }
     void                maybeThrowQhullMessage(int exitCode) const;
     void                maybeThrowQhullMessage(int exitCode, int noThrow) const;
 
 #//!\name Helpers
 private:
    QhullError           checkRunId() const;
    void                 checkUsingLibQhull() const;
 
 /***********************************
 You may use global variables in 'qh' after declaring UsingLibQhull.  For example
 
   UsingLibQhull q(qhRunId);
   // NOerrors -- no calls that throw libqhull errors
   cout << "Delaunay Mode: " << qh DELAUNAY;
 
 To trap errors from libqhull, UsingLibQhull must be followed by
 
 UsingLibQhull q(qhRunId);
 int exitCode = setjmp(qh errexit);
 if(!exitCode){ // no object creation -- destructors skipped on longjmp()
     calls to libqhull
 }
 q.maybeThrowQhullMessage(exitCode);
 
 The call to setjmp() can not be moved to a method.  The stack must be preserved for error exits from libqhull.
 
 */
 
 };//UsingLibQhull
 
 }//namespace orgQhull
 
 #endif // USINGlibqhull_H
diff --git a/src/libqhullcpp/functionObjects.h b/src/libqhullcpp/functionObjects.h
index e4da5f9..fb69d48 100644
--- a/src/libqhullcpp/functionObjects.h
+++ b/src/libqhullcpp/functionObjects.h
@@ -1,67 +1,67 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/functionObjects.h#8 $$Change: 1797 $
-** $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/functionObjects.h#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHFUNCTIONOBJECTS_H
 #define QHFUNCTIONOBJECTS_H
 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Defined here
 
     //! Sum of absolute values of the elements in a container
     class AbsoluteSumOf;
     //! Sum of the elements in a container
     class SumOf;
     //! Sum of squares of the elements in a container
     class SumSquaresOf;
 
 #//!\name Class
 
 //! Absolute sum of the elements in a container
 class AbsoluteSumOf
 {
 private:
     double sum;
 public:
     inline AbsoluteSumOf() : sum(0.0) {}
     inline void operator()(double v) { sum += fabs(v); }
     inline operator double() { return sum; }
 };//AbsoluteSumOf
 
 //! Sum of the elements in a container
 class SumOf
 {
 private:
     double sum;
 public:
     inline SumOf() : sum(0.0) {}
     inline void operator()(double v) { sum += v; }
     inline operator double() { return sum; }
 };//SumOf
 
 
 //! Sum of squares of the elements in a container
 class SumSquaresOf
 {
 private:
     double sum;
 public:
     inline SumSquaresOf() : sum(0.0) {}
     inline void operator()(double v) { sum += v*v; }
     inline operator double() { return sum; }
 };//SumSquaresOf
 
 
 }//orgQhull
 
 
 #endif //QHFUNCTIONOBJECTS_H
 
diff --git a/src/libqhullcpp/qt-qhull.cpp b/src/libqhullcpp/qt-qhull.cpp
index e42c67e..53573e4 100644
--- a/src/libqhullcpp/qt-qhull.cpp
+++ b/src/libqhullcpp/qt-qhull.cpp
@@ -1,130 +1,130 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullcpp/qt-qhull.cpp#7 $$Change: 1800 $
-** $DateTime: 2014/12/17 21:46:45 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullcpp/qt-qhull.cpp#8 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include 
 #include "RoadTest.h"
 
 #ifndef QHULL_USES_QT
 #define QHULL_USES_QT 1
 #endif
 
 #include "Coordinates.h"
 #include "QhullFacetList.h"
 #include "QhullFacetSet.h"
 #include "QhullHyperplane.h"
 #include "QhullPoint.h"
 #include "QhullPoints.h"
 #include "QhullPointSet.h"
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 
 namespace orgQhull {
 
 #//Conversions
 
 QList Coordinates::
 toQList() const
 {
     CoordinatesIterator i(*this);
     QList cs;
     while(i.hasNext()){
         cs.append(i.next());
     }
     return cs;
 }//toQList
 
 QList QhullFacetList::
 toQList() const
 {
     QhullLinkedListIterator i(*this);
     QList vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.append(f);
         }
     }
     return vs;
 }//toQList
 
 //! Same as PrintVertices
 QList QhullFacetList::
 vertices_toQList() const
 {
     QList vs;
     QhullVertexSet qvs(qh(), first().getFacetT(), NULL, isSelectAll());
     for(QhullVertexSet::iterator i=qvs.begin(); i!=qvs.end(); ++i){
         vs.push_back(*i);
     }
     return vs;
 }//vertices_toQList
 
 QList QhullFacetSet::
 toQList() const
 {
     QhullSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.append(f);
         }
     }
     return vs;
 }//toQList
 
 #ifdef QHULL_USES_QT
 QList QhullHyperplane::
 toQList() const
 {
     QhullHyperplaneIterator i(*this);
     QList fs;
     while(i.hasNext()){
         fs.append(i.next());
     }
     fs.append(hyperplane_offset);
     return fs;
 }//toQList
 #endif //QHULL_USES_QT
 
 QList QhullPoint::
 toQList() const
 {
     QhullPointIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 
 QList QhullPoints::
 toQList() const
 {
     QhullPointsIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 
 /******
 QList QhullPointSet::
 toQList() const
 {
     QhullPointSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 */
 }//orgQhull
 
diff --git a/src/libqhullpcpp/Coordinates.cpp b/src/libqhullpcpp/Coordinates.cpp
index 8352aea..008b1ab 100644
--- a/src/libqhullpcpp/Coordinates.cpp
+++ b/src/libqhullpcpp/Coordinates.cpp
@@ -1,184 +1,184 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/Coordinates.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/Coordinates.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "functionObjects.h"
 #include "QhullError.h"
 #include "Coordinates.h"
 
 #include 
 #include 
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//! Coordinates -- vector of coordT (normally double)
 
 #//Element access
 
 // Inefficient without result-value-optimization or implicitly shared object
 Coordinates Coordinates::
 mid(int idx, int length) const
 {
     int newLength= length;
     if(length<0 || idx+length > count()){
         newLength= count()-idx;
     }
     Coordinates result;
     if(newLength>0){
         std::copy(begin()+idx, begin()+(idx+newLength), std::back_inserter(result));
     }
     return result;
 }//mid
 
 coordT Coordinates::
 value(int idx, const coordT &defaultValue) const
 {
     return ((idx < 0 || idx >= count()) ? defaultValue : (*this)[idx]);
 }//value
 
 #//Operator
 
 Coordinates Coordinates::
 operator+(const Coordinates &other) const
 {
     Coordinates result(*this);
     std::copy(other.begin(), other.end(), std::back_inserter(result));
     return result;
 }//operator+
 
 Coordinates & Coordinates::
 operator+=(const Coordinates &other)
 {
     if(&other==this){
         Coordinates clone(other);
         std::copy(clone.begin(), clone.end(), std::back_inserter(*this));
     }else{
         std::copy(other.begin(), other.end(), std::back_inserter(*this));
     }
     return *this;
 }//operator+=
 
 #//Read-write
 
 coordT Coordinates::
 takeAt(int idx)
 {
     coordT c= at(idx);
     erase(begin()+idx);
     return c;
 }//takeAt
 
 coordT Coordinates::
 takeLast()
 {
     coordT c= last();
     removeLast();
     return c;
 }//takeLast
 
 void Coordinates::
 swap(int idx, int other)
 {
     coordT c= at(idx);
     at(idx)= at(other);
     at(other)= c;
 }//swap
 
 #//Search
 
 bool Coordinates::
 contains(const coordT &t) const
 {
     CoordinatesIterator i(*this);
     return i.findNext(t);
 }//contains
 
 int Coordinates::
 count(const coordT &t) const
 {
     CoordinatesIterator i(*this);
     int result= 0;
     while(i.findNext(t)){
         ++result;
     }
     return result;
 }//count
 
 int Coordinates::
 indexOf(const coordT &t, int from) const
 {
     if(from<0){
         from += count();
         if(from<0){
             from= 0;
         }
     }
     if(from(i-begin())); // WARN64
             }
             ++i;
         }
     }
     return -1;
 }//indexOf
 
 int Coordinates::
 lastIndexOf(const coordT &t, int from) const
 {
     if(from<0){
         from += count();
     }else if(from>=count()){
         from= count()-1;
     }
     if(from>=0){
         const_iterator i= begin()+from+1;
         while(i-- != constBegin()){
             if(*i==t){
                 return (static_cast(i-begin())); // WARN64
             }
         }
     }
     return -1;
 }//lastIndexOf
 
 void Coordinates::
 removeAll(const coordT &t)
 {
     MutableCoordinatesIterator i(*this);
     while(i.findNext(t)){
         i.remove();
     }
 }//removeAll
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::istream;
 using std::ostream;
 using std::string;
 using std::ws;
 using orgQhull::Coordinates;
 
 ostream &
 operator<<(ostream &os, const Coordinates &cs)
 {
     Coordinates::const_iterator c= cs.begin();
     for(int i=cs.count(); i--; ){
         os << *c++ << " ";
     }
     return os;
 }//operator<<
 
diff --git a/src/libqhullpcpp/Coordinates.h b/src/libqhullpcpp/Coordinates.h
index 1007660..a8923eb 100644
--- a/src/libqhullpcpp/Coordinates.h
+++ b/src/libqhullpcpp/Coordinates.h
@@ -1,312 +1,312 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/Coordinates.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/Coordinates.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHCOORDINATES_H
 #define QHCOORDINATES_H
 
 #include "QhullError.h"
 #include "QhullIterator.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 
 #include  // ptrdiff_t, size_t
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Types
     //! an allocated vector of point coordinates
     //!  Used by PointCoordinates for RboxPoints
     //!  A QhullPoint refers to previously allocated coordinates
     class Coordinates;
     class MutableCoordinatesIterator;
 
 
 class Coordinates {
 
 private:
 #//!\name Fields
     std::vector coordinate_array;
 
 public:
 #//!\name Subtypes
 
     class const_iterator;
     class iterator;
     typedef iterator Iterator;
     typedef const_iterator ConstIterator;
 
     typedef coordT              value_type;
     typedef const value_type   *const_pointer;
     typedef const value_type &  const_reference;
     typedef value_type *        pointer;
     typedef value_type &        reference;
     typedef ptrdiff_t           difference_type;
     typedef int                 size_type;
 
 #//!\name Construct
                         Coordinates() {};
     explicit            Coordinates(const std::vector &other) : coordinate_array(other) {}
                         Coordinates(const Coordinates &other) : coordinate_array(other.coordinate_array) {}
     Coordinates &       operator=(const Coordinates &other) { coordinate_array= other.coordinate_array; return *this; }
     Coordinates &       operator=(const std::vector &other) { coordinate_array= other; return *this; }
                         ~Coordinates() {}
 
 #//!\name Conversion
 
     coordT *            data() { return isEmpty() ? 0 : &at(0); }
     const coordT *      data() const { return const_cast(isEmpty() ? 0 : &at(0)); }
 
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const { return coordinate_array; }
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList      toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     int                count() const { return static_cast(size()); }
     bool               empty() const { return coordinate_array.empty(); }
     bool               isEmpty() const { return empty(); }
     bool               operator==(const Coordinates &other) const  { return coordinate_array==other.coordinate_array; }
     bool               operator!=(const Coordinates &other) const  { return coordinate_array!=other.coordinate_array; }
     size_t             size() const { return coordinate_array.size(); }
 
 #//!\name Element access
     coordT &            at(int idx) { return coordinate_array.at(idx); }
     const coordT &      at(int idx) const { return coordinate_array.at(idx); }
     coordT &            back() { return coordinate_array.back(); }
     const coordT &      back() const { return coordinate_array.back(); }
     coordT &            first() { return front(); }
     const coordT &      first() const { return front(); }
     coordT &            front() { return coordinate_array.front(); }
     const coordT &      front() const { return coordinate_array.front(); }
     coordT &            last() { return back(); }
     const coordT &      last() const { return back(); }
     Coordinates         mid(int idx, int length= -1) const;
     coordT &            operator[](int idx) { return coordinate_array.operator[](idx); }
     const coordT &      operator[](int idx) const { return coordinate_array.operator[](idx); }
     coordT              value(int idx, const coordT &defaultValue) const;
 
 #//!\name Iterator
     iterator            begin() { return iterator(coordinate_array.begin()); }
     const_iterator      begin() const { return const_iterator(coordinate_array.begin()); }
     const_iterator      constBegin() const { return begin(); }
     const_iterator      constEnd() const { return end(); }
     iterator            end() { return iterator(coordinate_array.end()); }
     const_iterator      end() const { return const_iterator(coordinate_array.end()); }
 
 #//!\name Read-only
     Coordinates         operator+(const Coordinates &other) const;
 
 #//!\name Modify
     void                append(const coordT &c) { push_back(c); }
     void                clear() { coordinate_array.clear(); }
     iterator            erase(iterator idx) { return iterator(coordinate_array.erase(idx.base())); }
     iterator            erase(iterator beginIterator, iterator endIterator) { return iterator(coordinate_array.erase(beginIterator.base(), endIterator.base())); }
     void                insert(int before, const coordT &c) { insert(begin()+before, c); }
     iterator            insert(iterator before, const coordT &c) { return iterator(coordinate_array.insert(before.base(), c)); }
     void                move(int from, int to) { insert(to, takeAt(from)); }
     Coordinates &       operator+=(const Coordinates &other);
     Coordinates &       operator+=(const coordT &c) { append(c); return *this; }
     Coordinates &       operator<<(const Coordinates &other) { return *this += other; }
     Coordinates &       operator<<(const coordT &c) { return *this += c; }
     void                pop_back() { coordinate_array.pop_back(); }
     void                pop_front() { removeFirst(); }
     void                prepend(const coordT &c) { insert(begin(), c); }
     void                push_back(const coordT &c) { coordinate_array.push_back(c); }
     void                push_front(const coordT &c) { insert(begin(), c); }
                         //removeAll below
     void                removeAt(int idx) { erase(begin()+idx); }
     void                removeFirst() { erase(begin()); }
     void                removeLast() { erase(--end()); }
     void                replace(int idx, const coordT &c) { (*this)[idx]= c; }
     void                reserve(int i) { coordinate_array.reserve(i); }
     void                swap(int idx, int other);
     coordT              takeAt(int idx);
     coordT              takeFirst() { return takeAt(0); }
     coordT              takeLast();
 
 #//!\name Search
     bool                contains(const coordT &t) const;
     int                 count(const coordT &t) const;
     int                 indexOf(const coordT &t, int from = 0) const;
     int                 lastIndexOf(const coordT &t, int from = -1) const;
     void                removeAll(const coordT &t);
 
 #//!\name Coordinates::iterator
     // From QhullPoints, forwarding to coordinate_array
     // before const_iterator for conversion with comparison operators
     class iterator {
 
     private:
         std::vector::iterator i;
         friend class const_iterator;
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef coordT      value_type;
         typedef value_type *pointer;
         typedef value_type &reference;
         typedef ptrdiff_t   difference_type;
 
                         iterator() {}
                         iterator(const iterator &other) { i= other.i; }
         explicit        iterator(const std::vector::iterator &vi) { i= vi; }
         iterator &      operator=(const iterator &other) { i= other.i; return *this; }
         std::vector::iterator &base() { return i; }
                         // No operator-> for base types
         coordT &        operator*() const { return *i; }
         coordT &        operator[](int idx) const { return i[idx]; }
 
         bool            operator==(const iterator &other) const { return i==other.i; }
         bool            operator!=(const iterator &other) const { return i!=other.i; }
         bool            operator<(const iterator &other) const { return i(const iterator &other) const { return i>other.i; }
         bool            operator>=(const iterator &other) const { return i>=other.i; }
               // reinterpret_cast to break circular dependency
         bool            operator==(const Coordinates::const_iterator &other) const { return *this==reinterpret_cast(other); }
         bool            operator!=(const Coordinates::const_iterator &other) const { return *this!=reinterpret_cast(other); }
         bool            operator<(const Coordinates::const_iterator &other) const { return *this(other); }
         bool            operator<=(const Coordinates::const_iterator &other) const { return *this<=reinterpret_cast(other); }
         bool            operator>(const Coordinates::const_iterator &other) const { return *this>reinterpret_cast(other); }
         bool            operator>=(const Coordinates::const_iterator &other) const { return *this>=reinterpret_cast(other); }
 
         iterator        operator++() { return iterator(++i); } //FIXUP QH11012 Should return reference, but get reference to temporary
         iterator        operator++(int) { return iterator(i++); }
         iterator        operator--() { return iterator(--i); }
         iterator        operator--(int) { return iterator(i--); }
         iterator        operator+=(int idx) { return iterator(i += idx); }
         iterator        operator-=(int idx) { return iterator(i -= idx); }
         iterator        operator+(int idx) const { return iterator(i+idx); }
         iterator        operator-(int idx) const { return iterator(i-idx); }
         difference_type operator-(iterator other) const { return i-other.i; }
     };//Coordinates::iterator
 
 #//!\name Coordinates::const_iterator
     class const_iterator {
 
     private:
         std::vector::const_iterator i;
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef coordT            value_type;
         typedef const value_type *pointer;
         typedef const value_type &reference;
         typedef ptrdiff_t         difference_type;
 
                         const_iterator() {}
                         const_iterator(const const_iterator &other) { i= other.i; }
                         const_iterator(iterator o) : i(o.i) {}
         explicit        const_iterator(const std::vector::const_iterator &vi) { i= vi; }
         const_iterator &operator=(const const_iterator &other) { i= other.i; return *this; }
                         // No operator-> for base types
                         // No reference to a base type for () and []
         const coordT &  operator*() const { return *i; }
         const coordT &  operator[](int idx) const { return i[idx]; }
 
         bool            operator==(const const_iterator &other) const { return i==other.i; }
         bool            operator!=(const const_iterator &other) const { return i!=other.i; }
         bool            operator<(const const_iterator &other) const { return i(const const_iterator &other) const { return i>other.i; }
         bool            operator>=(const const_iterator &other) const { return i>=other.i; }
 
         const_iterator  operator++() { return const_iterator(++i); } //FIXUP QH11014 -- too much copying
         const_iterator  operator++(int) { return const_iterator(i++); }
         const_iterator  operator--() { return const_iterator(--i); }
         const_iterator  operator--(int) { return const_iterator(i--); }
         const_iterator  operator+=(int idx) { return const_iterator(i += idx); }
         const_iterator  operator-=(int idx) { return const_iterator(i -= idx); }
         const_iterator  operator+(int idx) const { return const_iterator(i+idx); }
         const_iterator  operator-(int idx) const { return const_iterator(i-idx); }
         difference_type operator-(const_iterator other) const { return i-other.i; }
     };//Coordinates::const_iterator
 
 };//Coordinates
 
 //class CoordinatesIterator
 //QHULL_DECLARE_SEQUENTIAL_ITERATOR(Coordinates, coordT)
 
 class CoordinatesIterator
 {
     typedef Coordinates::const_iterator const_iterator;
     const Coordinates *c;
     const_iterator i;
     public:
     inline CoordinatesIterator(const Coordinates &container)
     : c(&container), i(c->constBegin()) {}
     inline CoordinatesIterator &operator=(const Coordinates &container)
     { c = &container; i = c->constBegin(); return *this; }
     inline void toFront() { i = c->constBegin(); }
     inline void toBack() { i = c->constEnd(); }
     inline bool hasNext() const { return i != c->constEnd(); }
     inline const coordT &next() { return *i++; }
     inline const coordT &peekNext() const { return *i; }
     inline bool hasPrevious() const { return i != c->constBegin(); }
     inline const coordT &previous() { return *--i; }
     inline const coordT &peekPrevious() const { const_iterator p = i; return *--p; }
     inline bool findNext(const coordT &t)
     { while (i != c->constEnd()) if (*i++ == t) return true; return false; }
     inline bool findPrevious(const coordT &t)
     { while (i != c->constBegin()) if (*(--i) == t) return true;
     return false;  }
 };//CoordinatesIterator
 
 //class MutableCoordinatesIterator
 //QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Coordinates, coordT)
 class MutableCoordinatesIterator
 {
     typedef Coordinates::iterator iterator;
     typedef Coordinates::const_iterator const_iterator;
     Coordinates *c;
     iterator i, n;
     inline bool item_exists() const { return const_iterator(n) != c->constEnd(); }
     public:
     inline MutableCoordinatesIterator(Coordinates &container)
     : c(&container)
     { i = c->begin(); n = c->end(); }
     inline ~MutableCoordinatesIterator()
     {}
     inline MutableCoordinatesIterator &operator=(Coordinates &container)
     { c = &container;
     i = c->begin(); n = c->end(); return *this; }
     inline void toFront() { i = c->begin(); n = c->end(); }
     inline void toBack() { i = c->end(); n = i; }
     inline bool hasNext() const { return c->constEnd() != const_iterator(i); }
     inline coordT &next() { n = i++; return *n; }
     inline coordT &peekNext() const { return *i; }
     inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); }
     inline coordT &previous() { n = --i; return *n; }
     inline coordT &peekPrevious() const { iterator p = i; return *--p; }
     inline void remove()
     { if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } }
     inline void setValue(const coordT &t) const { if (c->constEnd() != const_iterator(n)) *n = t; }
     inline coordT &value() { QHULL_ASSERT(item_exists()); return *n; }
     inline const coordT &value() const { QHULL_ASSERT(item_exists()); return *n; }
     inline void insert(const coordT &t) { n = i = c->insert(i, t); ++i; }
     inline bool findNext(const coordT &t)
     { while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; }
     inline bool findPrevious(const coordT &t)
     { while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true;
     n = c->end(); return false;  }
 };//MutableCoordinatesIterator
 
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::Coordinates &c);
 
 #endif // QHCOORDINATES_H
diff --git a/src/libqhullpcpp/PointCoordinates.cpp b/src/libqhullpcpp/PointCoordinates.cpp
index 5a23cc5..e671db4 100644
--- a/src/libqhullpcpp/PointCoordinates.cpp
+++ b/src/libqhullpcpp/PointCoordinates.cpp
@@ -1,295 +1,295 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/PointCoordinates.cpp#2 $$Change: 1712 $
-** $DateTime: 2014/03/30 22:34:33 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/PointCoordinates.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullError.h"
 #include "QhullPoint.h"
 #include "PointCoordinates.h"
 
 #include 
 #include 
 
 using std::istream;
 using std::string;
 using std::ws;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//! PointCoordinates -- vector of PointCoordinates
 
 #//Construct
 PointCoordinates::
 PointCoordinates()
 : QhullPoints()
 , point_coordinates()
 , point_comment()
 {
     makeValid();
 }
 
 #//Construct
 PointCoordinates::
 PointCoordinates(int pointDimension)
 : QhullPoints(pointDimension)
 , point_coordinates()
 , point_comment()
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(const std::string &aComment)
 : QhullPoints()
 , point_coordinates()
 , point_comment(aComment)
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(int pointDimension, const std::string &aComment)
 : QhullPoints(pointDimension)
 , point_coordinates()
 , point_comment(aComment)
 {
     makeValid();
 }
 
 PointCoordinates::
 PointCoordinates(int pointDimension, const std::string &aComment, int coordinatesCount, const coordT *c)
 : QhullPoints(pointDimension)
 , point_coordinates()
 , point_comment(aComment)
 {
     append(coordinatesCount, c);
 }
 
 PointCoordinates::
 PointCoordinates(const PointCoordinates &other)
 : QhullPoints(other)
 , point_coordinates(other.point_coordinates)
 , point_comment(other.point_comment)
 {
     makeValid();
 }
 
 PointCoordinates & PointCoordinates::
 operator=(const PointCoordinates &other)
 {
     QhullPoints::operator=(other);
     point_coordinates= other.point_coordinates;
     point_comment= other.point_comment;
     makeValid();
     return *this;
 }//operator=
 
 PointCoordinates::
 ~PointCoordinates()
 { }
 
 #//GetSet
 
 void PointCoordinates::
 checkValid() const
 {
     if(getCoordinates().data()!=data()
     || getCoordinates().count()!=coordinateCount()){
         throw QhullError(10060, "Qhull error: first point (%x) is not PointCoordinates.data() or count (%d) is not PointCoordinates.count (%d)", coordinateCount(), getCoordinates().count(), 0.0, data());
     }
 }//checkValid
 
 void PointCoordinates::
 setDimension(int i)
 {
     if(i<0){
         throw QhullError(10062, "Qhull error: can not set PointCoordinates dimension to %d", i);
     }
     int currentDimension=QhullPoints::dimension();
     if(currentDimension!=0 && i!=currentDimension){
         throw QhullError(10063, "Qhull error: can not change PointCoordinates dimension (from %d to %d)", currentDimension, i);
     }
     QhullPoints::setDimension(i);
 }//setDimension
 
 //#Foreach
 
 Coordinates::ConstIterator PointCoordinates::
 beginCoordinates(int pointIndex) const
 {
     return point_coordinates.begin()+indexOffset(pointIndex);
 }
 
 Coordinates::Iterator PointCoordinates::
 beginCoordinates(int pointIndex)
 {
     return point_coordinates.begin()+indexOffset(pointIndex);
 }
 
 #//Modify
 
 void PointCoordinates::
 append(int coordinatesCount, const coordT *c)
 {
     if(coordinatesCount<=0){
         return;
     }
     if(includesCoordinates(c)){
         throw QhullError(10065, "Qhull error: can not append a subset of PointCoordinates to itself.  The coordinates for point %d may move.", indexOf(c, QhullError::NOthrow));
     }
     reserveCoordinates(coordinatesCount);
     std::copy(c, c+coordinatesCount, std::back_inserter(point_coordinates));
     makeValid();
 }//append coordT
 
 void PointCoordinates::
 append(const PointCoordinates &other)
 {
     setDimension(other.dimension());
     append(other.coordinateCount(), other.data());
 }//append PointCoordinates
 
 void PointCoordinates::
 append(const QhullPoint &p)
 {
     setDimension(p.dimension());
     append(p.dimension(), p.coordinates());
 }//append QhullPoint
 
 void PointCoordinates::
 appendComment(const std::string &s){
     if(char c= s[0] && point_comment.empty()){
         if(c=='-' || isdigit(c)){
             throw QhullError(10028, "Qhull argument error: comments can not start with a number or minus, %s", 0, 0, 0.0, s.c_str());
         }
     }
     point_comment += s;
 }//appendComment
 
 //! Read PointCoordinates from istream.  First two numbers are dimension and count.  A non-digit starts a rboxCommand.
 //! Overwrites point_comment.  See qh_readpoints [io.c]
 void PointCoordinates::
 appendPoints(istream &in)
 {
     int inDimension, inCount;
     in >> ws >> inDimension >> ws;
     if(!in.good()){
         in.clear();
         string remainder;
         getline(in, remainder);
         throw QhullError(10005, "Qhull error: input did not start with dimension or count -- %s", 0, 0, 0, remainder.c_str());
     }
     char c= (char)in.peek();
     if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
         getline(in, point_comment);
         in >> ws;
     }
     in >> inCount >> ws;
     if(!in.good()){
         in.clear();
         string remainder;
         getline(in, remainder);
         throw QhullError(10009, "Qhull error: input did not start with dimension and count -- %d %s", inDimension, 0, 0, remainder.c_str());
     }
     c= (char)in.peek();
     if(c!='-' && !isdigit(c)){         // Comments start with a non-digit
         getline(in, point_comment);
         in >> ws;
     }
     if(inCount> p >> ws;
         if(in.fail()){
             in.clear();
             string remainder;
             getline(in, remainder);
             throw QhullError(10008, "Qhull error: failed to read coordinate %d  of point %d\n   %s", coordinatesCount % inDimension, coordinatesCount/inDimension, 0, remainder.c_str());
         }else{
             point_coordinates.push_back(p);
             coordinatesCount++;
         }
     }
     if(coordinatesCount != inCount*inDimension){
         if(coordinatesCount%inDimension==0){
             throw QhullError(10006, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates", int(inCount), inDimension, 0.0, int(coordinatesCount/inDimension));
         }else{
             throw QhullError(10012, "Qhull error: expected %d %d-d PointCoordinates but read %i PointCoordinates plus %f extra coordinates", inCount, inDimension, float(coordinatesCount%inDimension), coordinatesCount/inDimension);
         }
     }
     makeValid();
 }//appendPoints istream
 
 PointCoordinates PointCoordinates::
 operator+(const PointCoordinates &other) const
 {
     PointCoordinates pc= *this;
     pc << other;
     return pc;
 }//operator+
 
 void PointCoordinates::
 reserveCoordinates(int newCoordinates)
 {
     // vector::reserve is not const
     point_coordinates.reserve((int)point_coordinates.size()+newCoordinates); // WARN64
     makeValid();
 }//reserveCoordinates
 
 #//Helpers
 
 int PointCoordinates::
 indexOffset(int i) const {
     int n= i*dimension();
     int coordinatesCount= point_coordinates.count();
     if(i<0 || n>coordinatesCount){
         throw QhullError(10061, "Qhull error: point_coordinates is too short (%d) for point %d", coordinatesCount, i);
     }
     return n;
 }
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 
 using orgQhull::Coordinates;
 using orgQhull::PointCoordinates;
 
 ostream&
 operator<<(ostream &os, const PointCoordinates &p)
 {
     p.checkValid();
     int count= p.count();
     int dimension= p.dimension();
     string comment= p.comment();
     if(comment.empty()){
         os << dimension << endl;
     }else{
         os << dimension << " " << comment << endl;
     }
     os << count << endl;
     Coordinates::ConstIterator c= p.beginCoordinates();
     for(int i=0; i
 #include 
 
 namespace orgQhull {
 
 #//!\name Types
     //! Zero or more points with Coordinates, count, and dimension
     class PointCoordinates;
 
 class PointCoordinates : public QhullPoints {
 
 private:
 #//!\name Fields
     Coordinates         point_coordinates;      //! array of point coordinates
                                                 //! may have extraCoordinates()
     std::string         point_comment;          //! Comment describing PointCoordinates
 
 public:
 #//!\name Construct
                         PointCoordinates();
     explicit            PointCoordinates(int pointDimension);
     explicit            PointCoordinates(const std::string &aComment);
                         PointCoordinates(int pointDimension, const std::string &aComment);
                         PointCoordinates(int pointDimension, const std::string &aComment, int coordinatesCount, const coordT *c); // may be invalid
                         //! Use append() and appendPoints() for Coordinates and vector
                         PointCoordinates(const PointCoordinates &other);
     PointCoordinates &  operator=(const PointCoordinates &other);
                         ~PointCoordinates();
 
 #//!\name Convert
     //! QhullPoints coordinates, constData, data, count, size
 #ifndef QHULL_NO_STL
     void                append(const std::vector &otherCoordinates) { if(!otherCoordinates.empty()){ append((int)otherCoordinates.size(), &otherCoordinates[0]); } }
     std::vector toStdVector() const { return point_coordinates.toStdVector(); }
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     void                append(const QList &pointCoordinates) { if(!pointCoordinates.isEmpty()){ append(pointCoordinates.count(), &pointCoordinates[0]); } }
     QList       toQList() const { return point_coordinates.toQList(); }
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     //! See QhullPoints for coordinates, coordinateCount, dimension, empty, isEmpty, ==, !=
     void                checkValid() const;
     std::string         comment() const { return point_comment; }
     void                makeValid() { defineAs(point_coordinates.count(), point_coordinates.data()); }
     const Coordinates & getCoordinates() const { return point_coordinates; }
     void                setComment(const std::string &s) { point_comment= s; }
     void                setDimension(int i);
 
 private:
     void                defineAs(int coordinatesCount, coordT *c) { QhullPoints::defineAs(coordinatesCount, c); }
     //! defineAs() otherwise disabled
 public:
 
 #//!\name ElementAccess
     //! See QhullPoints for at, back, first, front, last, mid, [], value
 
 #//!\name Foreach
     //! See QhullPoints for begin, constBegin, end
     Coordinates::ConstIterator  beginCoordinates() const { return point_coordinates.begin(); }
     Coordinates::Iterator       beginCoordinates() { return point_coordinates.begin(); }
     Coordinates::ConstIterator  beginCoordinates(int pointIndex) const;
     Coordinates::Iterator       beginCoordinates(int pointIndex);
     Coordinates::ConstIterator  endCoordinates() const { return point_coordinates.end(); }
     Coordinates::Iterator       endCoordinates() { return point_coordinates.end(); }
 
 #//!\name Search
     //! See QhullPoints for contains, count, indexOf, lastIndexOf
 
 #//!\name Read-only
     PointCoordinates    operator+(const PointCoordinates &other) const;
 
 #//!\name Modify
     //FIXUP QH11001: Add clear() and other modify operators from Coordinates.h.  Include QhullPoint::operator=()
     void                append(int coordinatesCount, const coordT *c);  //! Dimension previously defined
     void                append(const coordT &c) { append(1, &c); } //! Dimension previously defined
     void                append(const QhullPoint &p);
     //! See convert for std::vector and QList
     void                append(const Coordinates &c) { append(c.count(), c.data()); }
     void                append(const PointCoordinates &other);
     void                appendComment(const std::string &s);
     void                appendPoints(std::istream &in);
     PointCoordinates &  operator+=(const PointCoordinates &other) { append(other); return *this; }
     PointCoordinates &  operator+=(const coordT &c) { append(c); return *this; }
     PointCoordinates &  operator+=(const QhullPoint &p) { append(p); return *this; }
     PointCoordinates &  operator<<(const PointCoordinates &other) { return *this += other; }
     PointCoordinates &  operator<<(const coordT &c) { return *this += c; }
     PointCoordinates &  operator<<(const QhullPoint &p) { return *this += p; }
     // reserve() is non-const
     void                reserveCoordinates(int newCoordinates);
 
 #//!\name Helpers
 private:
     int                 indexOffset(int i) const;
 
 };//PointCoordinates
 
 // No references to QhullPoint.  Prevents use of QHULL_DECLARE_SEQUENTIAL_ITERATOR(PointCoordinates, QhullPoint)
 class PointCoordinatesIterator
 {
     typedef PointCoordinates::const_iterator const_iterator;
     const PointCoordinates *c;
     const_iterator i;
     public:
     inline PointCoordinatesIterator(const PointCoordinates &container)
     : c(&container), i(c->constBegin()) {}
     inline PointCoordinatesIterator &operator=(const PointCoordinates &container)
     { c = &container; i = c->constBegin(); return *this; }
     inline void toFront() { i = c->constBegin(); }
     inline void toBack() { i = c->constEnd(); }
     inline bool hasNext() const { return i != c->constEnd(); }
     inline const QhullPoint next() { return *i++; }
     inline const QhullPoint peekNext() const { return *i; }
     inline bool hasPrevious() const { return i != c->constBegin(); }
     inline const QhullPoint previous() { return *--i; }
     inline const QhullPoint peekPrevious() const { const_iterator p = i; return *--p; }
     inline bool findNext(const QhullPoint &t)
     { while (i != c->constEnd()) if (*i++ == t) return true; return false; }
     inline bool findPrevious(const QhullPoint &t)
     { while (i != c->constBegin()) if (*(--i) == t) return true;
     return false;  }
 };//CoordinatesIterator
 
 // FIXUP QH11002:  Add MutablePointCoordinatesIterator after adding modify operators
 \
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &          operator<<(std::ostream &os, const orgQhull::PointCoordinates &p);
 
 #endif // QHPOINTCOORDINATES_H
diff --git a/src/libqhullpcpp/Qhull.cpp b/src/libqhullpcpp/Qhull.cpp
index ce6cd5e..9b160cd 100644
--- a/src/libqhullpcpp/Qhull.cpp
+++ b/src/libqhullpcpp/Qhull.cpp
@@ -1,543 +1,543 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/Qhull.cpp#2 $$Change: 1710 $
-** $DateTime: 2014/03/28 22:23:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/Qhull.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! Qhull -- invoke qhull from C++
 #//! Compile libqhull and Qhull together due to use of setjmp/longjmp()
 
 #include "QhullError.h"
 #include "UsingLibQhull.h"
 #include "RboxPoints.h"
 #include "QhullQh.h"
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "Qhull.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 
 using std::cerr;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//Global variables
 
 char s_unsupported_options[]=" Fd TI ";
 char s_not_output_options[]= " Fd TI A C d E H P Qb QbB Qbb Qc Qf Qg Qi Qm QJ Qr QR Qs Qt Qv Qx Qz Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 R Tc TC TM TP TR Tv TV TW U v V W ";
 
 #//Constructor, destructor, etc.
 Qhull::
 Qhull()
 : qhull_qh(0)
 , qhull_run_id(UsingLibQhull::NOqhRunId)
 , origin_point()
 , qhull_status(qh_ERRnone)
 , qhull_dimension(0)
 , run_called(false)
 , qh_active(false)
 , qhull_message()
 , error_stream(0)
 , output_stream(0)
 , feasiblePoint()
 , useOutputStream(false)
 {
     allocateQhullQh();
 }//Qhull
 
 Qhull::
 Qhull(const RboxPoints &rboxPoints, const char *qhullCommand2)
 : qhull_qh(0)
 , qhull_run_id(UsingLibQhull::NOqhRunId)
 , origin_point()
 , qhull_status(qh_ERRnone)
 , qhull_dimension(0)
 , run_called(false)
 , qh_active(false)
 , qhull_message()
 , error_stream(0)
 , output_stream(0)
 , feasiblePoint()
 , useOutputStream(false)
 {
     allocateQhullQh();
     runQhull(rboxPoints, qhullCommand2);
 }//Qhull rbox
 
 Qhull::
 Qhull(const char *rboxCommand2, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2)
 : qhull_qh(0)
 , qhull_run_id(UsingLibQhull::NOqhRunId)
 , origin_point()
 , qhull_status(qh_ERRnone)
 , qhull_dimension(0)
 , run_called(false)
 , qh_active(false)
 , qhull_message()
 , error_stream(0)
 , output_stream(0)
 , feasiblePoint()
 , useOutputStream(false)
 {
     allocateQhullQh();
     runQhull(rboxCommand2, pointDimension, pointCount, pointCoordinates, qhullCommand2);
 }//Qhull points
 
 Qhull::
 Qhull(const Qhull &other)
 : qhull_qh(0)
 , qhull_run_id(UsingLibQhull::NOqhRunId)
 , origin_point()
 , qhull_status(qh_ERRnone)
 , qhull_dimension(0)
 , run_called(false)
 , qh_active(false)
 , qhull_message(other.qhull_message)
 , error_stream(other.error_stream)
 , output_stream(other.output_stream)
 , feasiblePoint(other.feasiblePoint)
 , useOutputStream(other.useOutputStream)
 {
     if(other.initialized()){
         throw QhullError(10069, "Qhull error: can not use Qhull copy constructor if initialized() is true");
     }
     allocateQhullQh();
 }//copy constructor
 
 Qhull & Qhull::
 operator=(const Qhull &other)
 {
     if(other.initialized() || initialized()){
         throw QhullError(10070, "Qhull error: can not use Qhull copy assignment if initialized() is true");
     }
     qhull_message= other.qhull_message;
     error_stream= other.error_stream;
     output_stream= other.output_stream;
     feasiblePoint= other.feasiblePoint;
     useOutputStream= other.useOutputStream;
     return *this;
 }//copy constructor
 
 void Qhull::
 allocateQhullQh()
 {
     #if qh_QHpointer
         qhull_qh= new QhullQh;
         qhull_qh->old_qhstat= qh_qhstat;
         qhull_qh->old_tempstack= qhmem.tempstack;
         qh_qh= 0;
         qh_qhstat= 0;
     #else
         qhull_qh= new (&qh_qh) QhullQh;
         qhull_qh->old_qhstat= &qh_qhstat;
         qhull_qh->old_tempstack= qhmem.tempstack;
     #endif
     qhmem.tempstack= 0;
     qhull_run_id= qhull_qh->run_id;
 }//allocateQhullQh
 
 Qhull::
 ~Qhull() throw()
 {
     //! UsingLibQhull is required by ~QhullQh
     UsingLibQhull q(this, QhullError::NOthrow);
     if(q.defined()){
         int exitCode = setjmp(qh errexit);
         if(!exitCode){ // no object creation -- destructors skipped on longjmp()
 #if qh_QHpointer
             delete qhull_qh;
             // clears qhull_qh and qh_qh
             qh_qh= 0;
 #else
             qhull_qh->~QhullQh();
             qhull_qh= 0;
 #endif
             qhull_run_id= UsingLibQhull::NOqhRunId;
             // Except for cerr, does not throw errors
             if(hasQhullMessage()){
                 cerr<< "\nQhull output at end\n"; //FIXUP QH11005: where should error and log messages go on ~Qhull?
                 cerr<num_points*hullDimension(), qhull_qh->first_point);
 }//points
 
 QhullPointSet Qhull::
 otherPoints() const
 {
     return QhullPointSet(hullDimension(), qhull_qh->other_points);
 }//otherPoints
 
 //! Return vertices of the convex hull.
 QhullVertexList Qhull::
 vertexList() const{
     return QhullVertexList(beginVertex(), endVertex());
 }//vertexList
 
 #//Modify
 
 void Qhull::
 outputQhull()
 {
     checkIfQhullInitialized();
     UsingLibQhull q(this);
     int exitCode = setjmp(qh errexit);
     if(!exitCode){ // no object creation -- destructors skipped on longjmp()
         qh_produce_output2();
     }
     maybeThrowQhullMessage(exitCode);
 }//outputQhull
 
 void Qhull::
 outputQhull(const char *outputflags)
 {
     checkIfQhullInitialized();
     UsingLibQhull q(this);
     string cmd(" "); // qh_checkflags skips first word
     cmd += outputflags;
     char *command= const_cast(cmd.c_str());
     int exitCode = setjmp(qh errexit);
     if(!exitCode){ // no object creation -- destructors skipped on longjmp()
         qh_clear_outputflags();
         char *s = qh qhull_command + strlen(qh qhull_command) + 1; //space
         strncat(qh qhull_command, command, sizeof(qh qhull_command)-strlen(qh qhull_command)-1);
         qh_checkflags(command, s_not_output_options);
         qh_initflags(s);
         qh_initqhull_outputflags();
         if(qh KEEPminArea < REALmax/2
            || (0 != qh KEEParea + qh KEEPmerge + qh GOODvertex
                     + qh GOODthreshold + qh GOODpoint + qh SPLITthresholds)){
             facetT *facet;
             qh ONLYgood= False;
             FORALLfacet_(qh facet_list) {
                 facet->good= True;
             }
             qh_prepare_output();
         }
         qh_produce_output2();
         if(qh VERIFYoutput && !qh STOPpoint && !qh STOPcone){
             qh_check_points();
         }
     }
     maybeThrowQhullMessage(exitCode);
 }//outputQhull
 
 void Qhull::
 runQhull(const RboxPoints &rboxPoints, const char *qhullCommand2)
 {
     runQhull(rboxPoints.comment().c_str(), rboxPoints.dimension(), rboxPoints.count(), &*rboxPoints.coordinates(), qhullCommand2);
 }//runQhull, RboxPoints
 
 //! points is a array of points, input sites ('d' or 'v'), or halfspaces with offset last ('H')
 //! Derived from qh_new_qhull [user.c]
 void Qhull::
 runQhull(const char *rboxCommand2, int pointDimension, int pointCount, const realT *rboxPoints, const char *qhullCommand2)
 {
     if(run_called){
         throw QhullError(10027, "Qhull error: runQhull called twice.  Only one call allowed.");
     }
     run_called= true;
     string s("qhull ");
     s += qhullCommand2;
     char *command= const_cast(s.c_str());
     UsingLibQhull q(this);
     int exitCode = setjmp(qh errexit);
     if(!exitCode){ // no object creation -- destructors skipped on longjmp()
         qh_checkflags(command, s_unsupported_options);
         qh_initflags(command);
         *qh rbox_command= '\0';
         strncat( qh rbox_command, rboxCommand2, sizeof(qh rbox_command)-1);
         if(qh DELAUNAY){
             qh PROJECTdelaunay= True;   // qh_init_B() calls qh_projectinput()
         }
         pointT *newPoints= const_cast(rboxPoints);
         int newDimension= pointDimension;
         int newIsMalloc= False;
         if(qh HALFspace){
             --newDimension;
             initializeFeasiblePoint(newDimension);
             newPoints= qh_sethalfspace_all(pointDimension, pointCount, newPoints, qh feasible_point);
             newIsMalloc= True;
         }
         qh_init_B(newPoints, pointCount, newDimension, newIsMalloc);
         qhull_dimension= (qh DELAUNAY ? qh hull_dim - 1 : qh hull_dim);
         qh_qhull();
         qh_check_output();
         qh_prepare_output();
         if(qh VERIFYoutput && !qh STOPpoint && !qh STOPcone){
             qh_check_points();
         }
     }
     for(int k= qhull_dimension; k--; ){  // Do not move up (may throw)
         origin_point << 0.0;
     }
     maybeThrowQhullMessage(exitCode);
 }//runQhull
 
 #//Helpers -- be careful of allocating C++ objects due to setjmp/longjmp() error handling by qh_... routines
 
 void Qhull::
 initializeFeasiblePoint(int hulldim)
 {
     if(qh feasible_string){
         qh_setfeasible(hulldim);
     }else{
         if(feasiblePoint.empty()){
             qh_fprintf(qh ferr, 6209, "qhull error: missing feasible point for halfspace intersection.  Use option 'Hn,n' or set qh.feasiblePoint\n");
             qh_errexit(qh_ERRmem, NULL, NULL);
         }
         if(feasiblePoint.size()!=(size_t)hulldim){
             qh_fprintf(qh ferr, 6210, "qhull error: dimension of feasiblePoint should be %d.  It is %u", hulldim, feasiblePoint.size());
             qh_errexit(qh_ERRmem, NULL, NULL);
         }
         if (!(qh feasible_point= (coordT*)qh_malloc(hulldim * sizeof(coordT)))) {
             qh_fprintf(qh ferr, 6202, "qhull error: insufficient memory for feasible point\n");
             qh_errexit(qh_ERRmem, NULL, NULL);
         }
         coordT *t= qh feasible_point;
         // No qh_... routines after here -- longjmp() ignores destructor
         for(Coordinates::ConstIterator p=feasiblePoint.begin(); p--------------------------------
 
   qh_fprintf(fp, msgcode, format, list of args )
     fp is ignored (replaces qh_fprintf() in userprintf.c)
     s_qhull_output == Qhull
 
 notes:
     only called from libqhull
     same as fprintf() and RboxPoints::qh_fprintf_rbox()
     fgets() is not trapped like fprintf()
     Do not throw errors from here.  Use qh_errexit;
 */
 extern "C"
 void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ) {
     va_list args;
 
     using namespace orgQhull;
 
     if(!s_qhull_output){
         fprintf(stderr, "QH10025 Qhull error: UsingLibQhull not declared prior to calling qh_...().  s_qhull_output==NULL.\n");
         qh_exit(10025);
     }
     Qhull *out= s_qhull_output;
     va_start(args, fmt);
     if(msgcode=MSG_ERROR && msgcodeqhull_statusqhull_status>=MSG_WARNING){
                 out->qhull_status= msgcode;
             }
         }
         char newMessage[MSG_MAXLEN];
         // RoadError will add the message tag
         vsnprintf(newMessage, sizeof(newMessage), fmt, args);
         out->appendQhullMessage(newMessage);
         va_end(args);
         return;
     }
     if(out->output_stream && out->useOutputStream){
         char newMessage[MSG_MAXLEN];
         vsnprintf(newMessage, sizeof(newMessage), fmt, args);
         *out->output_stream << newMessage;
         va_end(args);
         return;
     }
     // FIXUP QH11008: how do users trap messages and handle input?  A callback?
     char newMessage[MSG_MAXLEN];
     vsnprintf(newMessage, sizeof(newMessage), fmt, args);
     out->appendQhullMessage(newMessage);
     va_end(args);
 } /* qh_fprintf */
 
diff --git a/src/libqhullpcpp/Qhull.h b/src/libqhullpcpp/Qhull.h
index 6ed6992..512aa25 100644
--- a/src/libqhullpcpp/Qhull.h
+++ b/src/libqhullpcpp/Qhull.h
@@ -1,147 +1,147 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/Qhull.h#3 $$Change: 1710 $
-** $DateTime: 2014/03/28 22:23:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/Qhull.h#4 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLCPP_H
 #define QHULLCPP_H
 
 #include "QhullQh.h"
 #include "RboxPoints.h"
 #include "QhullLinkedList.h"
 #include "QhullPoint.h"
 #include "QhullPoints.h"
 #include "QhullVertex.h"
 #include "QhullFacet.h"
 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 #if qh_QHpointer != 1
 #error  qh_QHpointer is not set.  Please set it in user.h or
 #error  compile Qhull with -Dqh_QHpointer.  The C++ classes
 #error  require dynamic allocation for Qhulls global data
 #error  structure qhT (QhullQh).
 #endif
 
 namespace orgQhull {
 
 /***
    Compile qhullcpp and libqhull with the same compiler.  setjmp() and longjmp() must be the same.
 */
 
 #//!\name Types
     //! Qhull -- run Qhull from C++
     class Qhull;
 
     //Defined elsewhere
     class QhullFacetList;
     class RboxPoints;
 
 class Qhull {
 
 private:
 #//!\name Members and friends
     QhullQh *           qhull_qh;       //! qh_qh for this instance
     int                 qhull_run_id;    //! qh.run_id at initialization (catch multiple runs if !qh_QHpointer)
     Coordinates         origin_point;   //! origin for qhull_dimension.  Set by runQhull()
     int                 qhull_status;   //! qh_ERRnone if valid
     int                 qhull_dimension; //! Dimension of result (qh.hull_dim or one less for Delaunay/Voronoi)
     bool                run_called;     //! True at start of runQhull.  Errors if call again.
     bool                qh_active;      //! True if global pointer qh_qh equals qhull_qh
     std::string         qhull_message;
     std::ostream *      error_stream;   //! overrides errorMessage, use appendQhullMessage()
     std::ostream *      output_stream;  //! send output to stream
 
     friend void       ::qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
     friend class UsingLibQhull;
 
 #//!\name Attribute
 public:
     Coordinates         feasiblePoint;  //! feasible point for half-space intersection
     bool                useOutputStream; //! Set if using outputStream
     // FIXUP QH11003 feasiblePoint useOutputStream as field or getter?
 
 #//!\name constructor, assignment, destructor, invariant
                         Qhull();      //! Qhull::runQhull() must be called next
                         Qhull(const RboxPoints &rboxPoints, const char *qhullCommand2);
                         Qhull(const char *rboxCommand2, int pointDimension, int pointCount, const realT *pointCoordinates, const char *qhullCommand2);
                         // Throws error if other.initialized().  Needed for return by value and parameter passing
                         Qhull(const Qhull &other);
                         // Throws error if initialized() or other.initialized().  Needed for vector
     Qhull &             operator=(const Qhull &other);
                         ~Qhull() throw();
 private:
     void                allocateQhullQh();
 
 public:
 #//!\name !\name virtual methods
     //FIXUP QH11004 -- qh_memfree, etc. as virtual?
 
 #//!\name Messaging
     void                appendQhullMessage(const std::string &s);
     void                clearQhullMessage();
     std::string         qhullMessage() const;
     bool                hasQhullMessage() const;
     int                 qhullStatus() const;
     void                setErrorStream(std::ostream *os);
     void                setOutputStream(std::ostream *os);
 
 #//!\name GetSet
     void                checkIfQhullInitialized();
     bool                initialized() const { return qhull_dimension>0; }
     int                 dimension() const { return qhull_dimension; }
     int                 hullDimension() const { return qhullQh()->hull_dim; }
                         // non-const due to QhullPoint
     QhullPoint          origin() { QHULL_ASSERT(initialized()); return QhullPoint(dimension(), origin_point.data()); }
     QhullQh *           qhullQh() const { return qhull_qh; };
     int                 runId(); // Modifies my_qhull
 
 #//!\name GetQh -- access to qhT (Qhull's global data structure)
     const char *        qhullCommand() const { return qhull_qh->qhull_command; }
     const char *        rboxCommand() const { return qhull_qh->rbox_command; }
     int                 facetCount() const { return qhull_qh->num_facets; }
     int                 vertexCount() const { return qhull_qh->num_vertices; }
 
 #//!\name GetValue
     double              area();
     double              volume();
 
 #//!\name ForEach
     QhullFacet          beginFacet() const { return QhullFacet(qhull_qh->facet_list); }
     QhullVertex         beginVertex() const { return QhullVertex(qhull_qh->vertex_list); }
     void                defineVertexNeighborFacets(); //!< Automatically called if merging facets or Voronoi diagram
     QhullFacet          endFacet() const { return QhullFacet(qhull_qh->facet_tail); }
     QhullVertex         endVertex() const { return QhullVertex(qhull_qh->vertex_tail); }
     QhullFacetList      facetList() const;
     QhullFacet          firstFacet() const { return beginFacet(); }
     QhullVertex         firstVertex() const { return beginVertex(); }
     QhullPoints         points() const;
     QhullPointSet       otherPoints() const;
                         //! Same as points().coordinates()
     coordT *            pointCoordinateBegin() const { return qhull_qh->first_point; }
     coordT *            pointCoordinateEnd() const { return qhull_qh->first_point + qhull_qh->num_points*qhull_qh->hull_dim; }
     QhullVertexList     vertexList() const;
 
 #//!\name Modify
     void                outputQhull();
     void                outputQhull(const char * outputflags);
     void                runQhull(const RboxPoints &rboxPoints, const char *qhullCommand2);
     void                runQhull(const char *rboxCommand2, int pointDimension, int pointCount, const realT *rboxPoints, const char *qhullCommand2);
 
 private:
 #//!\name Helpers
     void                initializeFeasiblePoint(int hulldim);
     void                maybeThrowQhullMessage(int exitCode);
     void                maybeThrowQhullMessage(int exitCode, int noThrow) throw();
 };//Qhull
 
 }//namespace orgQhull
 
 #endif // QHULLCPP_H
diff --git a/src/libqhullpcpp/QhullError.h b/src/libqhullpcpp/QhullError.h
index 8c9bc7c..757b146 100644
--- a/src/libqhullpcpp/QhullError.h
+++ b/src/libqhullpcpp/QhullError.h
@@ -1,65 +1,65 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullError.h#3 $$Change: 1710 $
-** $DateTime: 2014/03/28 22:23:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullError.h#4 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLERROR_H
 #define QHULLERROR_H
 
 #include "RoadError.h"
 // No dependencies on libqhull
 
 #include 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Types
     //! QhullError -- std::exception class for Qhull
     class QhullError;
 
 class QhullError : public RoadError {
 
 public:
 #//!\name Constants
     enum {
         QHULLfirstError= 10000, //MSG_QHULL_ERROR in Qhull's user.h
         QHULLlastError= 10073,
         NOthrow= 1 //! For flag to UsingLibQhull()
     };
 
 #//!\name Constructors
     // default constructors
     QhullError() : RoadError() {};
     QhullError(const QhullError &other) : RoadError(other) {}
     QhullError(int code, const std::string &message) : RoadError(code, message) {};
     QhullError(int code, const char *fmt) : RoadError(code, fmt) {};
     QhullError(int code, const char *fmt, int d) : RoadError(code, fmt, d) {};
     QhullError(int code, const char *fmt, int d, int d2) : RoadError(code, fmt, d, d2) {};
     QhullError(int code, const char *fmt, int d, int d2, float f) : RoadError(code, fmt, d, d2, f) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, const char *s) : RoadError(code, fmt, d, d2, f, s) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, const void *x) : RoadError(code, fmt, d, d2, f, x) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, int i) : RoadError(code, fmt, d, d2, f, i) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, long long i) : RoadError(code, fmt, d, d2, f, i) {};
     QhullError(int code, const char *fmt, int d, int d2, float f, double e) : RoadError(code, fmt, d, d2, f, e) {};
     QhullError &operator=(const QhullError &other) { this->RoadError::operator=(other); return *this; }
     ~QhullError() throw() {}
 
 };//class QhullError
 
 #ifndef QHULL_1
     #define QHULL_ASSERT assert
 
 #endif
 
 }//namespace orgQhull
 
 #//!\name Global
 
 inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullError &e) { return os << e.what(); }
 
 #endif // QHULLERROR_H
diff --git a/src/libqhullpcpp/QhullFacet.cpp b/src/libqhullpcpp/QhullFacet.cpp
index 6a0583e..990f620 100644
--- a/src/libqhullpcpp/QhullFacet.cpp
+++ b/src/libqhullpcpp/QhullFacet.cpp
@@ -1,524 +1,524 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacet.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacet.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullFacet -- Qhull's facet structure, facetT, as a C++ class
 
 #include "QhullError.h"
 #include "QhullSet.h"
 #include "QhullPoint.h"
 #include "QhullPointSet.h"
 #include "QhullRidge.h"
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 #include "QhullVertex.h"
 
 #include 
 
 using std::endl;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//class statics
 facetT QhullFacet::
         s_empty_facet= {0,0,0,0,{0},
                 0,0,0,0,0,
                 0,0,0,0,0,
                 0,0,0,0,0,
                 0,0,0,0,0,
                 0,0,0,0,0,
                 0,0,0,0,0,
                 0,0,0,0};
 
 #//GetSet
 
 int QhullFacet::
 dimension() const
 {
     if(qh_facet->ridges){
         setT *s= qh_facet->ridges;
         ridgeT *r= reinterpret_cast(SETfirst_(s));
         return r ? QhullSetBase::count(r->vertices)+1 : 0;
     }else{
         return QhullSetBase::count(qh_facet->vertices);
     }
 }//dimension
 
 //! Return voronoi center or facet centrum.  Derived from qh_printcenter [io.c]
 //! printFormat=qh_PRINTtriangles if return centrum of a Delaunay facet
 //! Sets center if needed
 //! Code duplicated for PrintCenter and getCenter
 //! .empty() if none or qh_INFINITE
 QhullPoint QhullFacet::
 getCenter(int qhRunId, qh_PRINT printFormat)
 {
     UsingLibQhull q(qhRunId);
 
     if(qh CENTERtype==qh_ASvoronoi){
         if(!qh_facet->normal || !qh_facet->upperdelaunay || !qh ATinfinity){
             if(!qh_facet->center){
                 int exitCode = setjmp(qh errexit);
                 if(!exitCode){ // no object creation -- destructors skipped on longjmp()
                     qh_facet->center= qh_facetcenter(qh_facet->vertices);
                 }
                 q.maybeThrowQhullMessage(exitCode);
             }
             return QhullPoint(qh hull_dim-1, qh_facet->center);
         }
     }else if(qh CENTERtype==qh_AScentrum){
         volatile int numCoords= qh hull_dim;
         if(printFormat==qh_PRINTtriangles && qh DELAUNAY){
             numCoords--;
         }
         if(!qh_facet->center){
             int exitCode = setjmp(qh errexit);
             if(!exitCode){ // no object creation -- destructors skipped on longjmp()
                 qh_facet->center= qh_getcentrum(getFacetT());
             }
             q.maybeThrowQhullMessage(exitCode);
         }
         return QhullPoint(numCoords, qh_facet->center);
     }
     return QhullPoint();
  }//getCenter
 
 //! Return innerplane clearly below the vertices
 //! from io.c[qh_PRINTinner]
 QhullHyperplane QhullFacet::
 innerplane(int qhRunId) const{
     UsingLibQhull q(qhRunId);
     realT inner;
     // Does not error
     qh_outerinner(const_cast(getFacetT()), NULL, &inner);
     QhullHyperplane h= hyperplane();
     h.setOffset(h.offset()-inner); //inner is negative
     return h;
 }//innerplane
 
 //! Return outerplane clearly above all points
 //! from io.c[qh_PRINTouter]
 QhullHyperplane QhullFacet::
 outerplane(int qhRunId) const{
     UsingLibQhull q(qhRunId);
     realT outer;
     // Does not error
     qh_outerinner(const_cast(getFacetT()), &outer, NULL);
     QhullHyperplane h= hyperplane();
     h.setOffset(h.offset()-outer); //outer is positive
     return h;
 }//outerplane
 
 //! Set by qh_triangulate for option 'Qt'.
 //! Errors if tricoplanar and facetArea() or qh_getarea() called first.
 QhullFacet QhullFacet::
 tricoplanarOwner() const
 {
     if(qh_facet->tricoplanar){
         if(qh_facet->isarea){
             throw QhullError(10018, "Qhull error: facetArea() or qh_getarea() previously called.  triCoplanarOwner() is not available.");
         }
         return qh_facet->f.triowner;
     }
     return 0; // FIXUP QH11009 Should false be the NULL facet or empty facet
 }//tricoplanarOwner
 
 QhullPoint QhullFacet::
 voronoiVertex(int qhRunId)
 {
     if(
 #if qh_QHpointer
       !qh_qh ||
 #endif
       qh CENTERtype!=qh_ASvoronoi){
           throw QhullError(10052, "Error: QhullFacet.voronoiVertex() requires option 'v' (qh_ASvoronoi)");
     }
     return getCenter(qhRunId);
 }//voronoiVertex
 
 #//Value
 
 //! Disables tricoplanarOwner()
 double QhullFacet::
 facetArea(int qhRunId)
 {
     if(!qh_facet->isarea){
         UsingLibQhull q(qhRunId);
         int exitCode = setjmp(qh errexit);
         if(!exitCode){ // no object creation -- destructors skipped on longjmp()
             qh_facet->f.area= qh_facetarea(qh_facet);
             qh_facet->isarea= True;
         }
         q.maybeThrowQhullMessage(exitCode);
     }
     return qh_facet->f.area;
 }//facetArea
 
 #//Foreach
 
 QhullPointSet QhullFacet::
 coplanarPoints() const
 {
     return QhullPointSet(dimension(), qh_facet->coplanarset);
 }//coplanarPoints
 
 QhullFacetSet QhullFacet::
 neighborFacets() const
 {
     return QhullFacetSet(qh_facet->neighbors);
 }//neighborFacets
 
 QhullPointSet QhullFacet::
 outsidePoints() const
 {
     return QhullPointSet(dimension(), qh_facet->outsideset);
 }//outsidePoints
 
 QhullRidgeSet QhullFacet::
 ridges() const
 {
     return QhullRidgeSet(qh_facet->ridges);
 }//ridges
 
 QhullVertexSet QhullFacet::
 vertices() const
 {
     return QhullVertexSet(qh_facet->vertices);
 }//vertices
 
 
 }//namespace orgQhull
 
 #//operator<<
 
 using std::ostream;
 
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetSet;
 using orgQhull::QhullPoint;
 using orgQhull::QhullPointSet;
 using orgQhull::QhullRidge;
 using orgQhull::QhullRidgeSet;
 using orgQhull::QhullSetBase;
 using orgQhull::QhullVertexSet;
 using orgQhull::UsingLibQhull;
 
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintFacet &pr)
 {
     QhullFacet f= *pr.facet;
     if(f.getFacetT()==0){ // Special values from set iterator
         os << " NULLfacet" << endl;
         return os;
     }
     if(f.getFacetT()==qh_MERGEridge){
         os << " MERGEridge" << endl;
         return os;
     }
     if(f.getFacetT()==qh_DUPLICATEridge){
         os << " DUPLICATEridge" << endl;
         return os;
     }
     os << f.printHeader(pr.run_id);
     if(!f.ridges().isEmpty()){
         os << f.printRidges(pr.run_id);
     }
     return os;
 }//operator<< PrintFacet
 
 //! Print Voronoi center or facet centrum to stream.  Same as qh_printcenter [io.c]
 //! Code duplicated for PrintCenter and getCenter
 //! Sets center if needed
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintCenter &pr)
 {
     facetT *f= pr.facet->getFacetT();
     if(qh CENTERtype!=qh_ASvoronoi && qh CENTERtype!=qh_AScentrum){
         return os;
     }
     if (pr.message){
         os << pr.message;
     }
     int numCoords;
     if(qh CENTERtype==qh_ASvoronoi){
         numCoords= qh hull_dim-1;
         if(!f->normal || !f->upperdelaunay || !qh ATinfinity){
             if(!f->center){
                 f->center= qh_facetcenter(f->vertices);
             }
             for(int k=0; kcenter[k] << " "; // FIXUP QH11010 qh_REAL_1
             }
         }else{
             for(int k=0; kcenter){
             f->center= qh_getcentrum(f);
         }
         for(int k=0; kcenter[k] << " "; // FIXUP QH11010 qh_REAL_1
         }
     }
     if(pr.print_format==qh_PRINTgeom && numCoords==2){
         os << " 0";
     }
     os << endl;
     return os;
 }//operator<< PrintCenter
 
 //! Print flags for facet to stream.  Space prefix.  From qh_printfacetheader [io.c]
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintFlags &p)
 {
     const facetT *f= p.facet->getFacetT();
     if(p.message){
         os << p.message;
     }
 
     os << (p.facet->isTopOrient() ? " top" : " bottom");
     if(p.facet->isSimplicial()){
         os << " simplicial";
     }
     if(p.facet->isTriCoplanar()){
         os << " tricoplanar";
     }
     if(p.facet->isUpperDelaunay()){
         os << " upperDelaunay";
     }
     if(f->visible){
         os << " visible";
     }
     if(f->newfacet){
         os << " new";
     }
     if(f->tested){
         os << " tested";
     }
     if(!f->good){
         os << " notG";
     }
     if(f->seen){
         os << " seen";
     }
     if(f->coplanar){
         os << " coplanar";
     }
     if(f->mergehorizon){
         os << " mergehorizon";
     }
     if(f->keepcentrum){
         os << " keepcentrum";
     }
     if(f->dupridge){
         os << " dupridge";
     }
     if(f->mergeridge && !f->mergeridge2){
         os << " mergeridge1";
     }
     if(f->mergeridge2){
         os << " mergeridge2";
     }
     if(f->newmerge){
         os << " newmerge";
     }
     if(f->flipped){
         os << " flipped";
     }
     if(f->notfurthest){
         os << " notfurthest";
     }
     if(f->degenerate){
         os << " degenerate";
     }
     if(f->redundant){
         os << " redundant";
     }
     os << endl;
     return os;
 }//operator<< PrintFlags
 
 //! Print header for facet to stream. Space prefix.  From qh_printfacetheader [io.c]
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintHeader &pr)
 {
     QhullFacet facet= *pr.facet;
     facetT *f= facet.getFacetT();
     os << "- f" << facet.id() << endl;
     os << facet.printFlags("    - flags:");
     if(f->isarea){
         os << "    - area: " << f->f.area << endl; //FIXUP QH11010 2.2g
     }else if(qh NEWfacets && f->visible && f->f.replace){
         os << "    - replacement: f" << f->f.replace->id << endl;
     }else if(f->newfacet){
         if(f->f.samecycle && f->f.samecycle != f){
             os << "    - shares same visible/horizon as f" << f->f.samecycle->id << endl;
         }
     }else if(f->tricoplanar /* !isarea */){
         if(f->f.triowner){
             os << "    - owner of normal & centrum is facet f" << f->f.triowner->id << endl;
         }
     }else if(f->f.newcycle){
         os << "    - was horizon to f" << f->f.newcycle->id << endl;
     }
     if(f->nummerge){
         os << "    - merges: " << f->nummerge << endl;
     }
     os << facet.hyperplane().print("    - normal: ", "\n    - offset: "); // FIXUP QH11010 %10.7g
     if(qh CENTERtype==qh_ASvoronoi || f->center){
         os << facet.printCenter(pr.run_id, qh_PRINTfacets, "    - center: ");
     }
 #if qh_MAXoutside
     if(f->maxoutside > qh DISTround){
         os << "    - maxoutside: " << f->maxoutside << endl; //FIXUP QH11010 %10.7g
     }
 #endif
     QhullPointSet ps= facet.outsidePoints();
     if(!ps.isEmpty()){
         QhullPoint furthest= ps.last();
         if (ps.size() < 6) {
             os << "    - outside set(furthest p" << furthest.id(pr.run_id) << "):" << endl;
             for(QhullPointSet::iterator i=ps.begin(); i!=ps.end(); ++i){
                 QhullPoint p= *i;
                 os << p.print(pr.run_id, "     ");
             }
         }else if(ps.size()<21){
             os << ps.print(pr.run_id, "    - outside set:");
         }else{
             os << "    - outside set:  " << ps.size() << " points.";
             os << furthest.print(pr.run_id, "  Furthest");
         }
 #if !qh_COMPUTEfurthest
         os << "    - furthest distance= " << f->furthestdist << endl; //FIXUP QH11010 %2.2g
 #endif
     }
     QhullPointSet cs= facet.coplanarPoints();
     if(!cs.isEmpty()){
         QhullPoint furthest= cs.last();
         if (cs.size() < 6) {
             os << "    - coplanar set(furthest p" << furthest.id(pr.run_id) << "):" << endl;
             for(QhullPointSet::iterator i=cs.begin(); i!=cs.end(); ++i){
                 QhullPoint p= *i;
                 os << p.print(pr.run_id, "     ");
             }
         }else if(cs.size()<21){
             os << cs.print(pr.run_id, "    - coplanar set:");
         }else{
             os << "    - coplanar set:  " << cs.size() << " points.";
             os << furthest.print(pr.run_id, "  Furthest");
         }
         zinc_(Zdistio);
         double d= facet.distance(furthest);
         os << "      furthest distance= " << d << endl; //FIXUP QH11010 %2.2g
     }
     QhullVertexSet vs= facet.vertices();
     if(!vs.isEmpty()){
         os << vs.print(pr.run_id, "    - vertices:");
     }
     QhullFacetSet fs= facet.neighborFacets();
     fs.selectAll();
     if(!fs.isEmpty()){
         os << fs.printIdentifiers("    - neighboring facets:");
     }
     return os;
 }//operator<< PrintHeader
 
 
 //! Print ridges of facet to stream.  Same as qh_printfacetridges [io.c]
 //! If qhRunId==UsingLibQhull::NOqhRunId, does not use qh
 ostream &
 operator<<(ostream &os, const QhullFacet::PrintRidges &pr)
 {
     const QhullFacet facet= *pr.facet;
     facetT *f= facet.getFacetT();
     QhullRidgeSet rs= facet.ridges();
     if(!rs.isEmpty()){
         if(pr.run_id!=UsingLibQhull::NOqhRunId){
             UsingLibQhull q(pr.run_id);
             // No calls to libqhull
             if(f->visible && qh NEWfacets){
                 os << "    - ridges(ids may be garbage):";
                 for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
                     QhullRidge r= *i;
                     os << " r" << r.id();
                 }
                 os << endl;
             }else{
                 os << "    - ridges:" << endl;
             }
         }else{
             os << "    - ridges:" << endl;
         }
 
         // Keep track of printed ridges
         for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
             QhullRidge r= *i;
             r.getRidgeT()->seen= false;
         }
         int ridgeCount= 0;
         if(facet.dimension()==3){
             for(QhullRidge r= rs.first(); !r.getRidgeT()->seen; r= r.nextRidge3d(facet)){
                 r.getRidgeT()->seen= true;
                 os << r.print(pr.run_id);
                 ++ridgeCount;
                 if(!r.hasNextRidge3d(facet)){
                     break;
                 }
             }
         }else {
             QhullFacetSet ns(facet.neighborFacets());
             for(QhullFacetSet::iterator i=ns.begin(); i!=ns.end(); ++i){
                 QhullFacet neighbor= *i;
                 QhullRidgeSet nrs(neighbor.ridges());
                 for(QhullRidgeSet::iterator j=nrs.begin(); j!=nrs.end(); ++j){
                     QhullRidge r= *j;
                     if(r.otherFacet(neighbor)==facet){
                         r.getRidgeT()->seen= true;
                         os << r.print(pr.run_id);
                         ridgeCount++;
                     }
                 }
             }
         }
         if(ridgeCount!=rs.count()){
             os << "     - all ridges:";
             for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
                 QhullRidge r= *i;
                 os << " r" << r.id();
             }
             os << endl;
         }
         for(QhullRidgeSet::iterator i=rs.begin(); i!=rs.end(); ++i){
             QhullRidge r= *i;
             if(!r.getRidgeT()->seen){
                 os << r.print(pr.run_id);
             }
         }
     }
     return os;
 }//operator<< PrintRidges
 
 // "No conversion" error if defined inline
 ostream &
 operator<<(ostream &os, QhullFacet &f)
 {
     os << f.print(UsingLibQhull::NOqhRunId);
     return os;
 }//<< QhullFacet
diff --git a/src/libqhullpcpp/QhullFacet.h b/src/libqhullpcpp/QhullFacet.h
index be9204f..e0d4beb 100644
--- a/src/libqhullpcpp/QhullFacet.h
+++ b/src/libqhullpcpp/QhullFacet.h
@@ -1,155 +1,155 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacet.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacet.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLFACET_H
 #define QHULLFACET_H
 
 #include "Coordinates.h"
 #include "QhullHyperplane.h"
 #include "QhullPoint.h"
 #include "QhullSet.h"
 #include "QhullPointSet.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name ClassRef
     class QhullFacetSet;
     class QhullRidge;
     typedef QhullSet  QhullRidgeSet;
     class QhullVertex;
     class QhullVertexSet;
 
 #//!\name Types
     //! QhullFacet -- Qhull's facet structure, facetT [libqhull.h], as a C++ class
     class QhullFacet;
 
 //! A QhullFacet is the C++ equivalent to Qhull's facetT*
 class QhullFacet {
 
 private:
 #//!\name Fields -- no additions (QhullFacetSet of facetT*)
     facetT *            qh_facet;  //! May be 0 (!isDefined) for corner cases (e.g., *facetSet.end()==0) and tricoplanarOwner()
 
 #//!\name Class objects
     static facetT       s_empty_facet; // needed for shallow copy
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
                         QhullFacet() : qh_facet(&s_empty_facet) {}
                         // Creates an alias.  Does not copy QhullFacet.  Needed for return by value and parameter passing
                         QhullFacet(const QhullFacet &o) : qh_facet(o.qh_facet ? o.qh_facet : &s_empty_facet) {}
                         // Creates an alias.  Does not copy QhullFacet.  Needed for vector
     QhullFacet &        operator=(const QhullFacet &o) { qh_facet= o.qh_facet ? o.qh_facet : &s_empty_facet; return *this; }
                         ~QhullFacet() {}
 
 #//!\name Conversion
                         //Implicit conversion from facetT
                         QhullFacet(facetT *f) : qh_facet(f ? f : &s_empty_facet) {}
                         // Do not define facetT().  It conflicts with return type facetT*
     facetT *            getFacetT() const { return qh_facet; }
 
 #//!\name QhullSet
     facetT *            getBaseT() const { return getFacetT(); }
 
 #//!\name getSet
     int                 dimension() const;
     QhullPoint          getCenter(int qhRunId) { return getCenter(qhRunId, qh_PRINTpoints); }
     QhullPoint          getCenter(int qhRunId, qh_PRINT printFormat);
     QhullHyperplane     hyperplane() const { return QhullHyperplane(dimension(), qh_facet->normal, qh_facet->offset); }
     int                 id() const { return qh_facet ? qh_facet->id : -1; }
     QhullHyperplane     innerplane(int qhRunId) const;
     bool                isDefined() const { return qh_facet && qh_facet != &s_empty_facet; }
     bool                isGood() const { return qh_facet && qh_facet->good; }
     bool                isSimplicial() const { return qh_facet->simplicial; }
     bool                isTopOrient() const { return qh_facet->toporient; }
     bool                isTriCoplanar() const { return qh_facet->tricoplanar; }
     bool                isUpperDelaunay() const { return qh_facet->upperdelaunay; }
     QhullFacet          next() const { return qh_facet->next; }
     bool                operator==(const QhullFacet &o) const { return qh_facet==o.qh_facet; }
     bool                operator!=(const QhullFacet &o) const { return !operator==(o); }
     QhullHyperplane     outerplane(int qhRunId) const;
     QhullFacet          previous() const { return qh_facet->previous; }
     QhullFacet          tricoplanarOwner() const;
     QhullPoint          voronoiVertex(int qhRunId);
 
 #//!\name value
     //! Undefined if c.size() != dimension()
     double              distance(const Coordinates &c) const { return distance(c.data()); }
     double              distance(const pointT *p) const { return distance(QhullPoint(dimension(), const_cast(p))); }
     double              distance(const QhullPoint &p) const { return hyperplane().distance(p); }
     double              facetArea(int qhRunId);
 
 #//!\name foreach
     // Can not inline.  Otherwise circular reference
     QhullPointSet       coplanarPoints() const;
     QhullFacetSet       neighborFacets() const;
     QhullPointSet       outsidePoints() const;
     QhullRidgeSet       ridges() const;
     QhullVertexSet      vertices() const;
 
 #//!\name IO
     struct PrintCenter{
         QhullFacet *    facet;  // non-const due to facet.center()
         const char *    message;
         int             run_id;
         qh_PRINT        print_format;
                         PrintCenter(int qhRunId, QhullFacet &f, qh_PRINT printFormat, const char * s) : facet(&f), message(s), run_id(qhRunId), print_format(printFormat){}
     };//PrintCenter
     PrintCenter         printCenter(int qhRunId, qh_PRINT printFormat, const char *message) { return PrintCenter(qhRunId, *this, printFormat, message); }
 
     struct PrintFacet{
         QhullFacet *    facet;  // non-const due to f->center()
         int             run_id;
                         PrintFacet(int qhRunId, QhullFacet &f) : facet(&f), run_id(qhRunId) {}
     };//PrintFacet
     PrintFacet          print(int qhRunId) { return PrintFacet(qhRunId, *this); }
 
     struct PrintFlags{
         const QhullFacet *facet;
         const char *    message;
                         PrintFlags(const QhullFacet &f, const char *s) : facet(&f), message(s) {}
     };//PrintFlags
     PrintFlags          printFlags(const char *message) const { return PrintFlags(*this, message); }
 
     struct PrintHeader{
         QhullFacet *    facet;  // non-const due to f->center()
         int             run_id;
                         PrintHeader(int qhRunId, QhullFacet &f) : facet(&f), run_id(qhRunId) {}
     };//PrintHeader
     PrintHeader         printHeader(int qhRunId) { return PrintHeader(qhRunId, *this); }
 
     struct PrintRidges{
         const QhullFacet *facet;
         int             run_id;
                         PrintRidges(int qhRunId, QhullFacet &f) : facet(&f), run_id(qhRunId) {}
     };//PrintRidges
     PrintRidges         printRidges(int qhRunId) { return PrintRidges(qhRunId, *this); }
 
 };//class QhullFacet
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintCenter &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintFlags &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintHeader &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintRidges &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacet::PrintFacet &pr);
 std::ostream &operator<<(std::ostream &os, orgQhull::QhullFacet &f); // non-const due to qh_getcenter()
 
 #endif // QHULLFACET_H
diff --git a/src/libqhullpcpp/QhullFacetList.cpp b/src/libqhullpcpp/QhullFacetList.cpp
index 22d4052..505a8fc 100644
--- a/src/libqhullpcpp/QhullFacetList.cpp
+++ b/src/libqhullpcpp/QhullFacetList.cpp
@@ -1,164 +1,164 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacetList.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacetList.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullFacetList -- Qhull's linked facets, as a C++ class
 
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "QhullPoint.h"
 #include "QhullRidge.h"
 #include "QhullVertex.h"
 
 using std::string;
 using std::vector;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//Conversion
 
 // See qt_qhull.cpp for QList conversions
 
 #ifndef QHULL_NO_STL
 std::vector QhullFacetList::
 toStdVector() const
 {
     QhullLinkedListIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.push_back(f);
         }
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #ifndef QHULL_NO_STL
 //! Same as PrintVertices
 std::vector QhullFacetList::
 vertices_toStdVector(int qhRunId) const
 {
     std::vector vs;
     QhullVertexSet qvs(qhRunId, first().getFacetT(), NULL, isSelectAll());
 
     for(QhullVertexSet::iterator i=qvs.begin(); i!=qvs.end(); ++i){
         vs.push_back(*i);
     }
     return vs;
 }//vertices_toStdVector
 #endif //QHULL_NO_STL
 
 #//Read-only
 
 bool QhullFacetList::
 contains(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullLinkedList::contains(facet);
     }
     for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             return true;
         }
     }
     return false;
 }//contains
 
 int QhullFacetList::
 count() const
 {
     if(isSelectAll()){
         return QhullLinkedList::count();
     }
     int counter= 0;
     for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
         if((*i).isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 int QhullFacetList::
 count(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullLinkedList::count(facet);
     }
     int counter= 0;
     for(QhullFacetList::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetList;
 using orgQhull::QhullVertex;
 using orgQhull::QhullVertexSet;
 using orgQhull::UsingLibQhull;
 
 ostream &
 operator<<(ostream &os, const QhullFacetList::PrintFacetList &pr)
 {
     QhullFacetList fs= *pr.facet_list;
     os << "Vertices for " << fs.count() << " facets" << endl;
     os << fs.printVertices(pr.run_id);
     os << fs.printFacets(pr.run_id);
     return os;
 }//operator<<
 
 //! Print facet list to stream.  From qh_printafacet [io.c]
 ostream &
 operator<<(ostream &os, const QhullFacetList::PrintFacets &pr)
 {
     for(QhullFacetList::const_iterator i= pr.facet_list->begin(); i != pr.facet_list->end(); ++i){
         QhullFacet f= *i;
         if(pr.facet_list->isSelectAll() || f.isGood()){
             os << f.print(pr.run_id);
         }
     }
     return os;
 }//printFacets
 
 //! Print vertices of good faces in facet list to stream.  From qh_printvertexlist [io.c]
 //! Same as vertices_toStdVector
 ostream &
 operator<<(ostream &os, const QhullFacetList::PrintVertices &pr)
 {
     QhullVertexSet vs(pr.run_id, pr.facet_list->first().getFacetT(), NULL, pr.facet_list->isSelectAll());
     for(QhullVertexSet::iterator i=vs.begin(); i!=vs.end(); ++i){
         QhullVertex v= *i;
         os << v.print(pr.run_id);
     }
     return os;
 }//printVertices
 
 std::ostream &
 operator<<(ostream &os, const QhullFacetList &fs)
 {
     os << fs.printFacets(UsingLibQhull::NOqhRunId);
     return os;
 }//QhullFacetList
 
diff --git a/src/libqhullpcpp/QhullFacetList.h b/src/libqhullpcpp/QhullFacetList.h
index bf1133e..ef8c537 100644
--- a/src/libqhullpcpp/QhullFacetList.h
+++ b/src/libqhullpcpp/QhullFacetList.h
@@ -1,102 +1,102 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacetList.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacetList.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLFACETLIST_H
 #define QHULLFACETLIST_H
 
 #include "QhullLinkedList.h"
 #include "QhullFacet.h"
 
 #include 
 
 namespace orgQhull {
 
 #//!\name ClassRef
     class QhullFacet;
 
 #//!\name Types
     //! QhullFacetList -- List of Qhull facets, as a C++ class.  See QhullFacetSet.h
     class QhullFacetList;
     //! QhullFacetListIterator -- if(f.isGood()){ ... }
     typedef QhullLinkedListIterator
                         QhullFacetListIterator;
 
 class QhullFacetList : public QhullLinkedList {
 
 #//!\name  Fields
 private:
     bool                select_all;   //! True if include bad facets.  Default is false.
 
 #//!\name Constructors
 public:
                         QhullFacetList(QhullFacet b, QhullFacet e) : QhullLinkedList(b, e), select_all(false) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullFacetList(const QhullFacetList &o) : QhullLinkedList(*o.begin(), *o.end()), select_all(o.select_all) {}
                         ~QhullFacetList() {}
 
 private:
                         //!Disable default constructor and copy assignment.  See QhullLinkedList
                         QhullFacetList();
     QhullFacetList &    operator=(const QhullFacetList &);
 public:
 
 #//!\name Conversion
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
     std::vector vertices_toStdVector(int qhRunId) const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList   toQList() const;
     QList  vertices_toQList(int qhRunId) const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     bool                isSelectAll() const { return select_all; }
     void                selectAll() { select_all= true; }
     void                selectGood() { select_all= false; }
 
 #//!\name Read-only
                         //! Filtered by facet.isGood().  May be 0 when !isEmpty().
     int                 count() const;
     bool                contains(const QhullFacet &f) const;
     int                 count(const QhullFacet &f) const;
                         //! operator==() does not depend on isGood()
 
 #//!\name IO
     struct PrintFacetList{
         const QhullFacetList *facet_list;
         int             run_id;
                         PrintFacetList(int qhRunId, const QhullFacetList &fl) : facet_list(&fl), run_id(qhRunId) {}
     };//PrintFacetList
     PrintFacetList     print(int qhRunId) const  { return PrintFacetList(qhRunId, *this); }
 
     struct PrintFacets{
         const QhullFacetList *facet_list;
         int             run_id;
                         PrintFacets(int qhRunId, const QhullFacetList &fl) : facet_list(&fl), run_id(qhRunId) {}
     };//PrintFacets
     PrintFacets     printFacets(int qhRunId) const { return PrintFacets(qhRunId, *this); }
 
     struct PrintVertices{
         const QhullFacetList *facet_list;
         int             run_id;   //! Can not be NOrunId due to qh_facetvertices
                         PrintVertices(int qhRunId, const QhullFacetList &fl) : facet_list(&fl), run_id(qhRunId) {}
     };//PrintVertices
     PrintVertices   printVertices(int qhRunId) const { return PrintVertices(qhRunId, *this); }
 };//class QhullFacetList
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintFacetList &p);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintFacets &p);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList::PrintVertices &p);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetList &fs);
 
 #endif // QHULLFACETLIST_H
diff --git a/src/libqhullpcpp/QhullFacetSet.cpp b/src/libqhullpcpp/QhullFacetSet.cpp
index d8e684c..21ab56c 100644
--- a/src/libqhullpcpp/QhullFacetSet.cpp
+++ b/src/libqhullpcpp/QhullFacetSet.cpp
@@ -1,145 +1,145 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacetSet.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullFacetSet.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullFacetSet -- Qhull's linked facets, as a C++ class
 
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 #include "QhullPoint.h"
 #include "QhullRidge.h"
 #include "QhullVertex.h"
 
 using std::string;
 using std::vector;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//Conversion
 
 // See qt-qhull.cpp for QList conversions
 
 #ifndef QHULL_NO_STL
 std::vector QhullFacetSet::
 toStdVector() const
 {
     QhullSetIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.push_back(f);
         }
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//Read-only
 
 bool QhullFacetSet::
 contains(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullSet::contains(facet);
     }
     for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             return true;
         }
     }
     return false;
 }//contains
 
 int QhullFacetSet::
 count() const
 {
     if(isSelectAll()){
         return QhullSet::count();
     }
     int counter= 0;
     for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f.isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 int QhullFacetSet::
 count(const QhullFacet &facet) const
 {
     if(isSelectAll()){
         return QhullSet::count(facet);
     }
     int counter= 0;
     for(QhullFacetSet::const_iterator i=begin(); i != end(); ++i){
         QhullFacet f= *i;
         if(f==facet && f.isGood()){
             counter++;
         }
     }
     return counter;
 }//count
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetSet;
 using orgQhull::UsingLibQhull;
 
 ostream &
 operator<<(ostream &os, const QhullFacetSet &fs)
 {
     os << fs.print(UsingLibQhull::NOqhRunId, "");
     return os;
 }//<begin(); i!=p.facet_set->end(); ++i){
         const QhullFacet f= *i;
         if(f.getFacetT()==qh_MERGEridge){
             os << " MERGE";
         }else if(f.getFacetT()==qh_DUPLICATEridge){
             os << " DUP";
         }else if(p.facet_set->isSelectAll() || f.isGood()){
             os << " f" << f.id();
         }
     }
     os << endl;
     return os;
 }//<
 
 namespace orgQhull {
 
 #//!\name ClassRef
     class QhullFacet;
 
 #//!\name Types
     //! QhullFacetSet -- a set of Qhull facets, as a C++ class.  See QhullFacetList.h
     class QhullFacetSet;
     typedef QhullSetIterator
                         QhullFacetSetIterator;
 
 class QhullFacetSet : public QhullSet {
 
 private:
 #//!\name Fields
     bool                select_all;   //! True if include bad facets.  Default is false.
 
 public:
 #//!\name Constructor
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
    explicit             QhullFacetSet(setT *s) : QhullSet(s), select_all(false) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullFacetSet(const QhullFacetSet &o) : QhullSet(o), select_all(o.select_all) {}
 
 private:
                         //!Disable default constructor and copy assignment.  See QhullSetBase
                         QhullFacetSet();
     QhullFacetSet &     operator=(const QhullFacetSet &);
 public:
 
 #//!\name Conversion
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList   toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     bool                isSelectAll() const { return select_all; }
     void                selectAll() { select_all= true; }
     void                selectGood() { select_all= false; }
 
 #//!\name Read-only
                         //! Filtered by facet.isGood().  May be 0 when !isEmpty().
     int                 count() const;
     bool                contains(const QhullFacet &f) const;
     int                 count(const QhullFacet &f) const;
                         //! operator==() does not depend on isGood()
 
 #//!\name IO
     // Not same as QhullFacetList#IO.  A QhullFacetSet is a component of a QhullFacetList.
 
     struct PrintFacetSet{
         const QhullFacetSet *facet_set;
         const char *    print_message;
         int             run_id;
                         PrintFacetSet(int qhRunId, const char *message, const QhullFacetSet *s) : facet_set(s), print_message(message), run_id(qhRunId) {}
     };//PrintFacetSet
     const PrintFacetSet       print(int qhRunId, const char *message) const { return PrintFacetSet(qhRunId, message, this); }
 
     struct PrintIdentifiers{
         const QhullFacetSet *facet_set;
         const char *    print_message;
                         PrintIdentifiers(const char *message, const QhullFacetSet *s) : facet_set(s), print_message(message) {}
     };//PrintIdentifiers
     PrintIdentifiers    printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }
 
 };//class QhullFacetSet
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet &fs);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet::PrintFacetSet &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullFacetSet::PrintIdentifiers &p);
 
 #endif // QHULLFACETSET_H
diff --git a/src/libqhullpcpp/QhullHyperplane.cpp b/src/libqhullpcpp/QhullHyperplane.cpp
index efaf4e9..48ca96d 100644
--- a/src/libqhullpcpp/QhullHyperplane.cpp
+++ b/src/libqhullpcpp/QhullHyperplane.cpp
@@ -1,166 +1,166 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullHyperplane.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullHyperplane.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullHyperplane.h"
 #include "QhullPoint.h"
 
 #include 
 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Conversion
 
 // See qt-qhull.cpp for QList conversions
 
 #ifndef QHULL_NO_STL
 std::vector QhullHyperplane::
 toStdVector() const
 {
     QhullHyperplaneIterator i(*this);
     std::vector fs;
     while(i.hasNext()){
         fs.push_back(i.next());
     }
     fs.push_back(hyperplane_offset);
     return fs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//Value
 
 //! Return distance from point to hyperplane.
 //!   If greater than zero, the point is above the facet (i.e., outside).
 // qh_distplane [geom.c], QhullFacet::distance, and QhullHyperplane::distance are copies
 //    Does not support RANDOMdist or logging
 double QhullHyperplane::
 distance(const QhullPoint &p) const
 {
     const coordT *point= p.coordinates();
     int dim= p.dimension();
     QHULL_ASSERT(dim==dimension());
     const coordT *normal= coordinates();
     double dist;
 
     switch (dim){
   case 2:
       dist= offset() + point[0] * normal[0] + point[1] * normal[1];
       break;
   case 3:
       dist= offset() + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
       break;
   case 4:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
       break;
   case 5:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
       break;
   case 6:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
       break;
   case 7:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
       break;
   case 8:
       dist= offset()+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
       break;
   default:
       dist= offset();
       for (int k=dim; k--; )
           dist += *point++ * *normal++;
       break;
     }
     return dist;
 }//distance
 
 double QhullHyperplane::
 norm() const {
     double d= 0.0;
     const coordT *c= coordinates();
     for (int k=dimension(); k--; ){
         d += *c * *c;
         ++c;
     }
     return sqrt(d);
 }//norm
 
 #//Operator
 
 bool QhullHyperplane::
 operator==(const QhullHyperplane &other) const
 {
     if(hyperplane_dimension!=other.hyperplane_dimension){
         return false;
     }
     double d= fabs(hyperplane_offset-other.hyperplane_offset);
     if(d>UsingLibQhull::globalDistanceEpsilon()){
         return false;
     }
     const coordT *c= hyperplane_coordinates;
     const coordT *c2= other.hyperplane_coordinates;
     if(c==c2){
         return true;
     }
     double dist2= 0.0;
     for(int k= hyperplane_dimension; k--; ){
         double diff= *c++ - *c2++;
         dist2 += diff*diff;
     }
     if(dist2 > UsingLibQhull::globalAngleEpsilon()){
         return false;
     }
     return true;
 }//operator==
 
 #//GetSet
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::ostream;
 using orgQhull::QhullHyperplane;
 using orgQhull::UsingLibQhull;
 
 #//operator<<
 
 ostream &
 operator<<(ostream &os, const QhullHyperplane &p)
 {
     os << p.print();
     return os;
 }
 
 ostream &
 operator<<(ostream &os, const QhullHyperplane::PrintHyperplane &pr)
 {
     QhullHyperplane p= *pr.hyperplane;
     if(pr.print_message){
         os << pr.print_message;
     }
     const realT *c= p.coordinates();
     for(int k=p.dimension(); k--; ){
         realT r= *c++;
         if(pr.print_message){
             os << " " << r; // FIXUP QH11010 %8.4g
         }else{
             os << " " << r; // FIXUP QH11010 qh_REAL_1
         }
     }
     if(pr.hyperplane_offset_message){
         os << pr.hyperplane_offset_message << " " << p.offset();
     }else{
         os << " " << p.offset();
     }
     os << std::endl;
     return os;
 }//PrintHyperplane
 
diff --git a/src/libqhullpcpp/QhullHyperplane.h b/src/libqhullpcpp/QhullHyperplane.h
index 4ceaaa1..ea966fe 100644
--- a/src/libqhullpcpp/QhullHyperplane.h
+++ b/src/libqhullpcpp/QhullHyperplane.h
@@ -1,122 +1,122 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullHyperplane.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullHyperplane.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHHYPERPLANE_H
 #define QHHYPERPLANE_H
 
 #include "QhullError.h"
 #include "QhullIterator.h"
 #include "UsingLibQhull.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 
 namespace orgQhull {
 #//!\name ClassRef
     class QhullPoint;
 
 #//!\name Types
     //! QhullHyperplane as an offset, dimension, and pointer to coordinates
     class QhullHyperplane;
     //! Java-style iterator for QhullHyperplane coordinates
     class QhullHyperplaneIterator;
 
 class QhullHyperplane { // Similar to QhullPoint
 
 private:
 #//!\name Fields
     coordT *            hyperplane_coordinates;  // Keep pointers aligned
     int                 hyperplane_dimension;
     coordT              hyperplane_offset;
 
 public:
 #//!\name Subtypes
     typedef const coordT *                  iterator;
     typedef const coordT *                  const_iterator;
     typedef QhullHyperplane::iterator       Iterator;
     typedef QhullHyperplane::const_iterator ConstIterator;
 
 #//!\name Construct
                         QhullHyperplane() : hyperplane_coordinates(0), hyperplane_dimension(0), hyperplane_offset(0.0) {};
                         QhullHyperplane(int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) : hyperplane_coordinates(c), hyperplane_dimension(hyperplaneDimension), hyperplane_offset(hyperplaneOffset) {}
                         // Creates an alias.  Does not copy the hyperplane's coordinates.  Needed for return by value and parameter passing.
                         QhullHyperplane(const QhullHyperplane &other)  : hyperplane_coordinates(other.hyperplane_coordinates), hyperplane_dimension(other.hyperplane_dimension), hyperplane_offset(other.hyperplane_offset) {}
                         // Creates an alias.  Does not copy the hyperplane's coordinates.  Needed for vector
     QhullHyperplane &   operator=(const QhullHyperplane &other) { hyperplane_coordinates= other.hyperplane_coordinates; hyperplane_dimension= other.hyperplane_dimension; hyperplane_offset= other.hyperplane_offset; return *this; }
                         ~QhullHyperplane() {}
 
 #//!\name Conversions --
 //! Includes offset at end
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList       toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name Read-only
 public:
     const coordT *      coordinates() const { return hyperplane_coordinates; }
     coordT *            coordinates() { return hyperplane_coordinates; }
     int                 dimension() const { return hyperplane_dimension; }
     bool                isDefined() const { return hyperplane_coordinates!=0 && hyperplane_dimension>0; }
     coordT              offset() const { return hyperplane_offset; }
 
 #//!\name Define
     void                defineAs(int hyperplaneDimension, coordT *c, coordT hyperplaneOffset) { QHULL_ASSERT(hyperplaneDimension>=0); hyperplane_coordinates= c; hyperplane_dimension= hyperplaneDimension; hyperplane_offset= hyperplaneOffset; }
     //! Creates an alias to other
     void                defineAs(QhullHyperplane &other) { hyperplane_coordinates= other.coordinates(); hyperplane_dimension= other.dimension();  hyperplane_offset= other.offset(); }
     void                setCoordinates(coordT *c) { hyperplane_coordinates= c; }
     void                setDimension(int hyperplaneDimension) { hyperplane_dimension= hyperplaneDimension; }
     void                setOffset(coordT hyperplaneOffset) { hyperplane_offset= hyperplaneOffset; }
 
 #//!\name value
     double              distance(const QhullPoint &p) const;
     double              norm() const;
 
 #//!\name iterator
     iterator            begin() { return hyperplane_coordinates; }
     const_iterator      begin() const { return hyperplane_coordinates; }
     const_iterator      constBegin() const { return hyperplane_coordinates; }
     const_iterator      constEnd() const { return hyperplane_coordinates+hyperplane_dimension; }
     int                 count() { return dimension(); }
     iterator            end() { return hyperplane_coordinates+hyperplane_dimension; }
     const_iterator      end() const { return hyperplane_coordinates+hyperplane_dimension; }
     size_t              size() { return (size_t)dimension(); }
 
 #//!\name Operator
     bool                operator==(const QhullHyperplane &other) const;
     bool                operator!=(const QhullHyperplane &other) const { return !operator==(other); }
     const coordT &      operator[](int idx) const { QHULL_ASSERT(idx>=0 && idx=0 && idx
 #include 
 #include 
 //! Avoid dependence on 
 namespace std { struct bidirectional_iterator_tag; struct random_access_iterator_tag; }
 
 namespace orgQhull {
 
 #//!\name Defined here
     //! QHULL_DECLARE_SEQUENTIAL_ITERATOR(C) -- Declare a Java-style iterator
     //! QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C) -- Declare a mutable Java-style iterator
     //! QHULL_DECLARE_SET_ITERATOR(C) -- Declare a set iterator
     //! QHULL_DECLARE_MUTABLE_SET_ITERATOR(C) -- Declare a mutable set iterator
     //! Derived from Qt/core/tools/qiterator.h and qset.h/FOREACHsetelement_()
 
 // Changed c to C* as in Mutable...  Assumes c does not go away.
 #define QHULL_DECLARE_SEQUENTIAL_ITERATOR(C, T) \
     \
     class C##Iterator \
     { \
         typedef C::const_iterator const_iterator; \
         const C *c; \
         const_iterator i; \
         public: \
         inline C##Iterator(const C &container) \
         : c(&container), i(c->constBegin()) {} \
         inline C##Iterator &operator=(const C &container) \
         { c = &container; i = c->constBegin(); return *this; } \
         inline void toFront() { i = c->constBegin(); } \
         inline void toBack() { i = c->constEnd(); } \
         inline bool hasNext() const { return i != c->constEnd(); } \
         inline const T &next() { return *i++; } \
         inline const T &peekNext() const { return *i; } \
         inline bool hasPrevious() const { return i != c->constBegin(); } \
         inline const T &previous() { return *--i; } \
         inline const T &peekPrevious() const { const_iterator p = i; return *--p; } \
         inline bool findNext(const T &t) \
         { while (i != c->constEnd()) if (*i++ == t) return true; return false; } \
         inline bool findPrevious(const T &t) \
         { while (i != c->constBegin()) if (*(--i) == t) return true; \
         return false;  } \
     };//C##Iterator
 
 // Remove setShareable() from Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR
 // Uses QHULL_ASSERT (assert.h)
 // Duplicated in MutablePointIterator without insert or remove
 #define QHULL_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C, T) \
     class Mutable##C##Iterator \
     { \
         typedef C::iterator iterator; \
         typedef C::const_iterator const_iterator; \
         C *c; \
         iterator i, n; \
         inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
         public: \
         inline Mutable##C##Iterator(C &container) \
         : c(&container) \
         { i = c->begin(); n = c->end(); } \
         inline ~Mutable##C##Iterator() \
         {} \
         inline Mutable##C##Iterator &operator=(C &container) \
         { c = &container; \
         i = c->begin(); n = c->end(); return *this; } \
         inline void toFront() { i = c->begin(); n = c->end(); } \
         inline void toBack() { i = c->end(); n = i; } \
         inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
         inline T &next() { n = i++; return *n; } \
         inline T &peekNext() const { return *i; } \
         inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
         inline T &previous() { n = --i; return *n; } \
         inline T &peekPrevious() const { iterator p = i; return *--p; } \
         inline void remove() \
         { if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } } \
         inline void setValue(const T &t) const { if (c->constEnd() != const_iterator(n)) *n = t; } \
         inline T &value() { QHULL_ASSERT(item_exists()); return *n; } \
         inline const T &value() const { QHULL_ASSERT(item_exists()); return *n; } \
         inline void insert(const T &t) { n = i = c->insert(i, t); ++i; } \
         inline bool findNext(const T &t) \
         { while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; } \
         inline bool findPrevious(const T &t) \
         { while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true; \
         n = c->end(); return false;  } \
     };//Mutable##C##Iterator
 
 #define QHULL_DECLARE_SET_ITERATOR(C) \
 \
     template  \
     class Qhull##C##Iterator \
     { \
         typedef typename Qhull##C::const_iterator const_iterator; \
         Qhull##C c; \
         const_iterator i; \
     public: \
         inline Qhull##C##Iterator(const Qhull##C &container) \
         : c(container), i(c.constBegin()) {} \
         inline Qhull##C##Iterator &operator=(const Qhull##C &container) \
         { c = container; i = c.constBegin(); return *this; } \
         inline void toFront() { i = c.constBegin(); } \
         inline void toBack() { i = c.constEnd(); } \
         inline bool hasNext() const { return i != c.constEnd(); } \
         inline const T &next() { return *i++; } \
         inline const T &peekNext() const { return *i; } \
         inline bool hasPrevious() const { return i != c.constBegin(); } \
         inline const T &previous() { return *--i; } \
         inline const T &peekPrevious() const { const_iterator p = i; return *--p; } \
         inline bool findNext(const T &t) \
         { while (i != c.constEnd()) if (*i++ == t) return true; return false; } \
         inline bool findPrevious(const T &t) \
         { while (i != c.constBegin()) if (*(--i) == t) return true; \
         return false;  } \
     };//Qhull##C##Iterator
 
 #define QHULL_DECLARE_MUTABLE_SET_ITERATOR(C) \
 \
 template  \
 class QhullMutable##C##Iterator \
 { \
     typedef typename Qhull##C::iterator iterator; \
     typedef typename Qhull##C::const_iterator const_iterator; \
     Qhull##C *c; \
     iterator i, n; \
     inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
 public: \
     inline Mutable##C##Iterator(Qhull##C &container) \
         : c(&container) \
     { c->setSharable(false); i = c->begin(); n = c->end(); } \
     inline ~Mutable##C##Iterator() \
     { c->setSharable(true); } \
     inline Mutable##C##Iterator &operator=(Qhull##C &container) \
     { c->setSharable(true); c = &container; c->setSharable(false); \
       i = c->begin(); n = c->end(); return *this; } \
     inline void toFront() { i = c->begin(); n = c->end(); } \
     inline void toBack() { i = c->end(); n = i; } \
     inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
     inline T &next() { n = i++; return *n; } \
     inline T &peekNext() const { return *i; } \
     inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
     inline T &previous() { n = --i; return *n; } \
     inline T &peekPrevious() const { iterator p = i; return *--p; } \
     inline void remove() \
     { if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } } \
     inline void setValue(const T &t) const { if (c->constEnd() != const_iterator(n)) *n = t; } \
     inline T &value() { Q_ASSERT(item_exists()); return *n; } \
     inline const T &value() const { Q_ASSERT(item_exists()); return *n; } \
     inline void insert(const T &t) { n = i = c->insert(i, t); ++i; } \
     inline bool findNext(const T &t) \
     { while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; } \
     inline bool findPrevious(const T &t) \
     { while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true; \
       n = c->end(); return false;  } \
 };//QhullMutable##C##Iterator
 
 }//namespace orgQhull
 
 #endif // QHULLITERATOR_H
 
diff --git a/src/libqhullpcpp/QhullLinkedList.h b/src/libqhullpcpp/QhullLinkedList.h
index 6eacbb6..0853411 100644
--- a/src/libqhullpcpp/QhullLinkedList.h
+++ b/src/libqhullpcpp/QhullLinkedList.h
@@ -1,375 +1,375 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullLinkedList.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullLinkedList.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLLINKEDLIST_H
 #define QHULLLINKEDLIST_H
 
 namespace std { struct bidirectional_iterator_tag; struct random_access_iterator_tag; }
 
 #include "QhullError.h"
 
 #ifdef QHULL_USES_QT
 #include 
 #endif
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Type
     //! QhullLinkedList -- A linked list modeled on QLinkedList.
     //!   T is an opaque type with T(B *b), b=t.getBaseT(), t=t.next(), and t=t.prev().  The end node is a sentinel.
     //!   libqhull owns the contents.
     //!   QhullLinkedList does not define erase(), clear(), removeFirst(), removeLast(), pop_back(), pop_front(), fromStdList()
     //!   Derived from Qt/core/tools/qlinkedlist.h and libqhull.h/FORALLfacets_()
     //! QhullLinkedList::const_iterator -- STL-style iterator
     //! QhullLinkedList::iterator -- STL-style iterator
     //! QhullLinkedListIterator -- Java-style iterator
     //!   Derived from Qt/core/tools/qiterator.h
     //!   Works with Qt's foreach keyword [Qt/src/corelib/global/qglobal.h]
 
 template 
 class QhullLinkedList
 {
 private:
 #//!\name Fields
     T                   begin_node;
     T                   end_node;     //! Sentinel node at end of list
 
 public:
 #//!\name Subtypes and types
     class const_iterator;
     class iterator;
     typedef const_iterator  ConstIterator;
     typedef iterator    Iterator;
     typedef ptrdiff_t   difference_type;
     typedef int         size_type;
     typedef T           value_type;
     typedef const value_type *const_pointer;
     typedef const value_type &const_reference;
     typedef value_type *pointer;
     typedef value_type &reference;
 
 #//!\name Constructors
                         QhullLinkedList(T b, T e) : begin_node(b), end_node(e) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullLinkedList(const QhullLinkedList &o) : begin_node(o.begin_node), end_node(o.end_node) {}
                         ~QhullLinkedList() {}
 
 private:
                         //!disabled since a sentinel must be allocated as the private type
                         QhullLinkedList() {}
                         //!disabled since qs= qs2 is ambiguous (pointer vs. contents)
     QhullLinkedList &operator=(const QhullLinkedList &l) {}
 public:
 
 #//!\name Conversions
 #ifndef QHULL_NO_STL
     std::vector      toStdVector() const;
 #endif
 #ifdef QHULL_USES_QT
     QList            toQList() const;
 #endif
 
 #//!\name Read-only
     int                 count() const;
                         //count(t) under Search
     bool                empty() const { return isEmpty(); }
     bool                isEmpty() const { return (begin_node==end_node); }
     bool                operator==(const QhullLinkedList &o) const;
     bool                operator!=(const QhullLinkedList &o) const { return !operator==(o); }
     size_t              size() const { return count(); }
 
 #//!\name Element access
     //! Return by value which contains a pointer (e.g., typedef vertexT * QhullVertex).  A reference does not make sense.
     T                   back() const { return last(); }
     T                   first() const { QHULL_ASSERT(!isEmpty()); return *begin(); }
     T                   front() const { return first(); }
     T                   last() const { QHULL_ASSERT(!isEmpty()); return *--end(); }
 
 #//!\name Modify -- Allocation of opaque types not implemented.
 
 #//!\name Search
     bool                contains(const T &t) const;
     int                 count(const T &t) const;
 
 #//!\name Iterator
     iterator            begin() { return begin_node; }
     const_iterator      begin() const { return begin_node; }
     const_iterator      constBegin() const { return begin_node; }
     const_iterator      constEnd() const { return end_node; }
     iterator            end() { return end_node; }
     const_iterator      end() const { return end_node; }
 
     class iterator {
 
     private:
         T               i;
         friend class const_iterator;
 
     public:
         typedef std::bidirectional_iterator_tag  iterator_category;
         typedef T           value_type;
         typedef value_type *pointer;
         typedef value_type &reference;
         typedef ptrdiff_t   difference_type;
 
                         iterator() : i() {}
                         iterator(T t) : i(t) {}
                         iterator(const iterator &o) : i(o.i) {}
         iterator &      operator=(const iterator &o) { i= o.i; return *this; }
 
         T               operator*() const { return i; }
         T               operator->() const { return i; }
         bool            operator==(const iterator &o) const { return i == o.i; }
         bool            operator!=(const iterator &o) const { return !operator==(o); }
         bool            operator==(const const_iterator &o) const { return i==reinterpret_cast(o).i; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
         iterator &      operator++() { i= i.next(); return *this; }
         iterator        operator++(int) { iterator o= i; i= i.next(); return o; }
         iterator &      operator--() { i= i.previous(); return *this; }
         iterator        operator--(int) { iterator o= i; i= i.previous(); return o; }
         iterator        operator+(int j) const;
         iterator        operator-(int j) const { return operator+(-j); }
         iterator &      operator+=(int j) { return *this= *this + j; }
         iterator &      operator-=(int j) { return *this= *this - j; }
     };//QhullLinkedList::iterator
 
     class const_iterator {
 
     private:
         T               i;
 
     public:
         typedef std::bidirectional_iterator_tag  iterator_category;
         typedef T                 value_type;
         typedef const value_type *pointer;
         typedef const value_type &reference;
         typedef ptrdiff_t         difference_type;
 
                         const_iterator() : i() {}
                         const_iterator(T t) : i(t) {}
                         const_iterator(const const_iterator &o) : i(o.i) {}
                         const_iterator(iterator o) : i(o.i) {}
         const_iterator &operator=(const const_iterator &o) { i= o.i; return *this; }
 
         T               operator*() const { return i; }
         T               operator->() const { return i; }
         bool            operator==(const const_iterator &o) const { return i == o.i; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
                         // No comparisons or iterator diff
         const_iterator &operator++() { i= i.next(); return *this; }
         const_iterator  operator++(int) { const_iterator o= i; i= i.next(); return o; }
         const_iterator &operator--() { i= i.previous(); return *this; }
         const_iterator  operator--(int) { const_iterator o= i; i= i.previous(); return o; }
         const_iterator  operator+(int j) const;
         const_iterator  operator-(int j) const { return operator+(-j); }
         const_iterator &operator+=(int j) { return *this= *this + j; }
         const_iterator &operator-=(int j) { return *this= *this - j; }
     };//QhullLinkedList::const_iterator
 
 };//QhullLinkedList
 
 template 
 class QhullLinkedListIterator // FIXUP QH11016 define QhullMutableLinkedListIterator
 {
     typedef typename QhullLinkedList::const_iterator const_iterator;
     const QhullLinkedList *c;
     const_iterator      i;
 
 public:
                         QhullLinkedListIterator(const QhullLinkedList &container) : c(&container), i(c->constBegin()) {}
                         QhullLinkedListIterator &operator=(const QhullLinkedList &container) { c= &container; i= c->constBegin(); return *this; }
     bool                findNext(const T &t);
     bool                findPrevious(const T &t);
     bool                hasNext() const { return i != c->constEnd(); }
     bool                hasPrevious() const { return i != c->constBegin(); }
     T                   next() { return *i++; }
     T                   peekNext() const { return *i; }
     T                   peekPrevious() const { const_iterator p= i; return *--p; }
     T                   previous() { return *--i; }
     void                toFront() { i= c->constBegin(); }
     void                toBack() { i= c->constEnd(); }
 };//QhullLinkedListIterator
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
 template 
 std::vector QhullLinkedList::
 toStdVector() const
 {
     std::vector tmp;
     std::copy(constBegin(), constEnd(), std::back_inserter(tmp));
     return tmp;
 }//toStdVector
 #endif
 
 #ifdef QHULL_USES_QT
 template 
 QList  QhullLinkedList::
 toQList() const
 {
     QhullLinkedListIterator i(*this);
     QList ls;
     while(i.hasNext()){
         ls.append(i.next());
     }
     return ls;
 }//toQList
 #endif
 
 #//!\name Read-only
 
 template 
 int QhullLinkedList::
 count() const
 {
     const_iterator i= begin_node;
     int c= 0;
     while(i != end_node){
         c++;
         i++;
     }
     return c;
 }//count
 
 #//!\name Search
 
 template 
 bool QhullLinkedList::
 contains(const T &t) const
 {
     const_iterator i= begin_node;
     while(i != end_node){
         if(i==t){
             return true;
         }
         i++;
     }
     return false;
 }//contains
 
 template 
 int QhullLinkedList::
 count(const T &t) const
 {
     const_iterator i= begin_node;
     int c= 0;
     while(i != end_node){
         if(i==t){
             c++;
         }
         i++;
     }
     return c;
 }//count
 
 template 
 bool QhullLinkedList::
 operator==(const QhullLinkedList &l) const
 {
     if(begin_node==l.begin_node){
         return (end_node==l.end_node);
     }
     T i= begin_node;
     T il= l.begin_node;
     while(i != end_node){
         if(i != il){
             return false;
         }
         i= static_cast(i.next());
         il= static_cast(il.next());
     }
     if(il != l.end_node){
         return false;
     }
     return true;
 }//operator==
 
 #//!\name Iterator
 
 template 
 typename QhullLinkedList::iterator  QhullLinkedList::iterator::
 operator+(int j) const
 {
     T n= i;
     if(j>0){
         while(j--){
             n= n.next();
         }
     }else{
         while(j++){
             n= n.previous();
         }
     }
     return iterator(n);
 }//operator+
 
 template 
 typename QhullLinkedList::const_iterator  QhullLinkedList::const_iterator::
 operator+(int j) const
 {
     T n= i;
     if(j>0){
         while(j--){
             n= n.next();
         }
     }else{
         while(j++){
             n= n.previous();
         }
     }
     return const_iterator(n);
 }//operator+
 
 #//!\name QhullLinkedListIterator
 
 template 
 bool QhullLinkedListIterator::
 findNext(const T &t)
 {
     while(i != c->constEnd()){
         if (*i++ == t){
             return true;
         }
     }
     return false;
 }//findNext
 
 template 
 bool QhullLinkedListIterator::
 findPrevious(const T &t)
 {
     while(i!=c->constBegin()){
         if(*(--i)==t){
             return true;
         }
     }
     return false;
 }//findNext
 
 }//namespace orgQhull
 
 #//!\name Global
 
 template 
 std::ostream &
 operator<<(std::ostream &os, const orgQhull::QhullLinkedList &qs)
 {
     typename orgQhull::QhullLinkedList::const_iterator i;
     for(i= qs.begin(); i != qs.end(); ++i){
         os << *i;
     }
     return os;
 }//operator<<
 
 #endif // QHULLLINKEDLIST_H
 
diff --git a/src/libqhullpcpp/QhullPoint.cpp b/src/libqhullpcpp/QhullPoint.cpp
index 9bb26a3..b562d20 100644
--- a/src/libqhullpcpp/QhullPoint.cpp
+++ b/src/libqhullpcpp/QhullPoint.cpp
@@ -1,177 +1,177 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullPoint.cpp#3 $$Change: 1711 $
-** $DateTime: 2014/03/30 12:48:17 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullPoint.cpp#4 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "UsingLibQhull.h"
 #include "QhullPoint.h"
 
 #include 
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Class public variables and methods
 
 //! If qhRundID undefined uses QhullPoint::s_points_begin and dimension
 int QhullPoint::
 id(int qhRunId, int dimension, const coordT *c)
 {
     QHULL_UNUSED(dimension);
 
     if(UsingLibQhull::hasPoints()){
         if(qhRunId==UsingLibQhull::NOqhRunId){
             const coordT *pointsEnd;
             int dim;
             const coordT *points= UsingLibQhull::globalPoints(&dim, &pointsEnd);
             if(c>=points && c(c));
         }
     }
     long long i=(long long)c;
     return (int)i; // WARN64
 }//id
 
 #//Conversion
 
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 std::vector QhullPoint::
 toStdVector() const
 {
     QhullPointIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//Operator
 
 //! QhullPoint is equal if it has the same address and dimension, or if the coordinates are within sqrt(qh_qh->distanceEpsilon())
 //! Uses sqrt() since globalDistanceEpsilon is the roundoff for distance to hyperplane, i.e., the inner product
 bool QhullPoint::
 operator==(const QhullPoint &other) const
 {
     if(point_dimension!=other.point_dimension){
         return false;
     }
     const coordT *c= point_coordinates;
     const coordT *c2= other.point_coordinates;
     if(c==c2){
         return true;
     }
     double dist2= 0.0;
     for(int k= point_dimension; k--; ){
         double diff= *c++ - *c2++;
         dist2 += diff*diff;
     }
     return (dist2 <= UsingLibQhull::globalDistanceEpsilon());
  }//operator==
 
 
 #//Value
 
 //! Return distance between two points.
 double QhullPoint::
 distance(const QhullPoint &p) const
 {
     const coordT *c= coordinates();
     const coordT *c2= p.coordinates();
     int dim= dimension();
     QHULL_ASSERT(dim==p.dimension());
     double dist;
 
     switch(dim){
   case 2:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]);
       break;
   case 3:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]);
       break;
   case 4:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]);
       break;
   case 5:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]);
       break;
   case 6:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]);
       break;
   case 7:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]) + (c[6]-c2[6])*(c[6]-c2[6]);
       break;
   case 8:
       dist= (c[0]-c2[0])*(c[0]-c2[0]) + (c[1]-c2[1])*(c[1]-c2[1]) + (c[2]-c2[2])*(c[2]-c2[2]) + (c[3]-c2[3])*(c[3]-c2[3]) + (c[4]-c2[4])*(c[4]-c2[4]) + (c[5]-c2[5])*(c[5]-c2[5]) + (c[6]-c2[6])*(c[6]-c2[6]) + (c[7]-c2[7])*(c[7]-c2[7]);
       break;
   default:
       dist= 0.0;
       for(int k=dim; k--; ){
           dist += (*c - *c2) * (*c - *c2);
           ++c;
           ++c2;
       }
       break;
     }
     return sqrt(dist);
 }//distance
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::UsingLibQhull;
 
 #//operator<<
 
 ostream &
 operator<<(ostream &os, const QhullPoint &p)
 {
     os << p.printWithIdentifier(UsingLibQhull::NOqhRunId, "");
     return os;
 }
 
 //! Same as qh_printpointid [io.c]
 ostream &
 operator<<(ostream &os, const QhullPoint::PrintPoint &pr)
 {
     QhullPoint p= *pr.point;
     int i= p.id(pr.run_id);
     if(pr.point_message){
         if(*pr.point_message){
             os << pr.point_message << " ";
         }
         if(pr.with_identifier && (i!=-1)){
             os << "p" << i << ": ";
         }
     }
     const realT *c= p.coordinates();
     for(int k=p.dimension(); k--; ){
         realT r= *c++;
         if(pr.point_message){
             os << " " << r; // FIXUP QH11010 %8.4g
         }else{
             os << " " << r; // FIXUP QH11010 qh_REAL_1
         }
     }
     os << std::endl;
     return os;
 }//printPoint
 
diff --git a/src/libqhullpcpp/QhullPoint.h b/src/libqhullpcpp/QhullPoint.h
index 66b6dc2..3a3432c 100644
--- a/src/libqhullpcpp/QhullPoint.h
+++ b/src/libqhullpcpp/QhullPoint.h
@@ -1,130 +1,130 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullPoint.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullPoint.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHPOINT_H
 #define QHPOINT_H
 
 #include "QhullError.h"
 #include "QhullIterator.h"
 #include "UsingLibQhull.h"
 #include "Coordinates.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name Types
     //! QhullPoint as a pointer and dimension to shared memory
     class QhullPoint;
     //! Java-style iterator for QhullPoint coordinates
     class QhullPointIterator;
 
 class QhullPoint {
 
     //! A point is a pointer into an array of coordinates.
 
 private:
 #//!\name Fields
     coordT *            point_coordinates;  // Keep pointers aligned
     int                 point_dimension;
 
 public:
 #//!\name Subtypes
     typedef const coordT *              iterator;
     typedef const coordT *              const_iterator;
     typedef QhullPoint::iterator        Iterator;
     typedef QhullPoint::const_iterator  ConstIterator;
 
 #//!\name Class methods -- Convert point to id w/o QhullQh data structure
     static int          id(const coordT *c) { return QhullPoint::id(UsingLibQhull::NOqhRunId, 0, c); }
     static int          id(int qhRunId, const coordT *c) { return QhullPoint::id(qhRunId, 0, c); }
     static int          id(int qhRunId, int dimension, const coordT *c);
 
 #//!\name Construct
                         QhullPoint() : point_coordinates(0), point_dimension(0) {};
                         QhullPoint(int pointDimension, coordT *c) : point_coordinates(c), point_dimension(pointDimension) {}
     explicit            QhullPoint(Coordinates &c) : point_coordinates(c.data()), point_dimension(c.count()) {}
                         // Creates an alias.  Does not copy the point.  Needed for return by value and parameter passing.
                         QhullPoint(const QhullPoint &other)  : point_coordinates(other.point_coordinates), point_dimension(other.point_dimension) {}
                         // Creates an alias.  Does not copy the point.  Needed for vector
     QhullPoint &        operator=(const QhullPoint &other) { point_coordinates= other.point_coordinates; point_dimension= other.point_dimension; return *this; }
                         ~QhullPoint() {}
 
 #//!\name Conversions
     // see coordinates()
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList       toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name Read-only
 public:
     const coordT *      coordinates() const { return point_coordinates; }
     coordT *            coordinates() { return point_coordinates; }
     int                 dimension() const { return point_dimension; }
     int                 id(int qhRunId) const { return id(qhRunId, dimension(), coordinates()); }
     int                 id() const { return id(UsingLibQhull::NOqhRunId, dimension(), coordinates()); }
     bool                isDefined() const { return point_coordinates!=0 && point_dimension>0; }
 
 #//!\name Define
     void                advancePoint(int idx) { point_coordinates += idx*point_dimension; }
     void                defineAs(int pointDimension, coordT *c) { QHULL_ASSERT(pointDimension>=0); point_coordinates= c; point_dimension= pointDimension; }
     //! Creates an alias to other
     void                defineAs(QhullPoint &other) { point_coordinates= other.coordinates(); point_dimension= other.dimension(); }
     void                setCoordinates(coordT *c) { point_coordinates= c; }
     void                setDimension(int pointDimension) { point_dimension= pointDimension; }
 
 #//!\name value
     double              distance(const QhullPoint &p) const;
 
 #//!\name iterator
     iterator            begin() { return point_coordinates; }
     const_iterator      begin() const { return point_coordinates; }
     const_iterator      constBegin() const { return point_coordinates; }
     const_iterator      constEnd() const { return point_coordinates+point_dimension; }
     int                 count() { return dimension(); }
     iterator            end() { return point_coordinates+point_dimension; }
     const_iterator      end() const { return point_coordinates+point_dimension; }
     size_t              size() { return (size_t)dimension(); }
 
 #//!\name Operator
     bool                operator==(const QhullPoint &other) const;
     bool                operator!=(const QhullPoint &other) const { return !operator==(other); }
     const coordT &      operator[](int idx) const { QHULL_ASSERT(idx>=0 && idx=0 && idx
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #// Conversion
 
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 std::vector QhullPointSet::
 toStdVector() const
 {
     QhullPointSetIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//Element-access
 //! Derived from QhullSet::value
 QhullPoint QhullPointSet::
 value(int idx) const
 {
     // Avoid call to qh_setsize() and assert in elementPointer()
     //const T *n= reinterpret_cast(&SETelem_(getSetT(), idx));
     void **n= reinterpret_cast(&SETelem_(getSetT(), idx));
     coordT **n2= reinterpret_cast(n);
     if(idx>=0 && n(&SETelem_(getSetT(), idx));
     coordT **n2= reinterpret_cast(n);
     if(idx>=0 && nconstEnd()){
         if(*i++ == p){
             return true;
         }
     }
     return false;
 }//findNext
 
 bool QhullPointSetIterator::
 findPrevious(const QhullPoint &p)
 {
     while(i!=c->constBegin()){
         if(*(--i) == p){
             return true;
         }
     }
     return false;
 }//findPrevious
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::QhullPointSet;
 using orgQhull::UsingLibQhull;
 
 #//operator<<
 
 ostream &
 operator<<(ostream &os, const QhullPointSet &ps)
 {
     os << ps.print(UsingLibQhull::NOqhRunId);
     return os;
 }//<
 
 namespace orgQhull {
 
 #//!\name Types
     //! QhullPointSet -- a set of coordinate pointers with dimension
     // with const_iterator and iterator
     class QhullPointSet;
     //! Java-style iterator
     class QhullPointsIterator;
 
 #//!\name Classref
     class QhullPoint;
 
 class QhullPointSet : public QhullSet {
 
 private:
 #//!\name Fields
     int                 point_dimension;
 
 public:
 #//!\name Subtypes and types
     class const_iterator;
     class iterator;
     typedef QhullPointSet::const_iterator ConstIterator;
     typedef QhullPointSet::iterator Iterator;
 
     typedef QhullPoint  value_type;
     typedef ptrdiff_t   difference_type;
     typedef int         size_type;
     //typedef const value_type *const_pointer;    // FIXUP QH11019: QhullPointSet does not define pointer or reference due to point_dimension
     //typedef const value_type &const_reference;
     //typedef value_type *pointer;
     //typedef value_type &reference;
 
 #//!\name Construct
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
                         QhullPointSet(int pointDimension, setT *s) : QhullSet(s), point_dimension(pointDimension) {}
                         //Copy constructor copies pointer but not contents.  Needed for return by value and parameter passing.
                         QhullPointSet(const QhullPointSet &o) : QhullSet(o), point_dimension(o.point_dimension) {}
                         ~QhullPointSet() {}
 
 //Default constructor and copy assignment disabled since p= p2 is ambiguous (coord* vs coord)
 private:
                         QhullPointSet();
     QhullPointSet &     operator=(const QhullPointSet &);
 public:
 
 #//!\name Conversions
     // inherited -- constData, data
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif
 #ifdef QHULL_USES_QT
     QList   toQList() const;
 #endif
 
 #//!\name Read-only
     //inherits count, empty, isEmpty, size
     using QhullSetBase::count;
     int                 dimension() const { return point_dimension; }
     bool                operator==(const QhullPointSet &o) const;
     bool                operator!=(const QhullPointSet &o) const { return !operator==(o); }
 
 #//!\name Element access
     //! Can not return references since QhullPoint must be generated
     QhullPoint          at(int idx) const { return operator[](idx); }
     QhullPoint          back() const { return last(); }
     //! end element is NULL
     QhullPoint          first() const { QHULL_ASSERT(!isEmpty()); return *begin(); }
     QhullPoint          front() const { return first(); }
     QhullPoint          last() const { QHULL_ASSERT(!isEmpty()); return *(end()-1); }
     // mid() not available.  No setT constructor
     QhullPoint          operator[](int idx) const { return QhullPoint(dimension(), QhullSet::operator[](idx)); }
     QhullPoint          second()  const { return operator[](1); }
     QhullPoint          value(int idx) const;
     // Non-const since copy is an alias
     QhullPoint          value(int idx, QhullPoint &defaultValue) const;
 
 #//!\name iterator
     iterator            begin() { return iterator(dimension(), reinterpret_cast(beginPointer())); }
     const_iterator      begin() const { return const_iterator(dimension(), reinterpret_cast(beginPointer())); }
     const_iterator      constBegin() const { return const_iterator(dimension(), reinterpret_cast(beginPointer())); }
     const_iterator      constEnd() const { return const_iterator(dimension(), reinterpret_cast(endPointer())); }
     iterator            end() { return iterator(dimension(), reinterpret_cast(endPointer())); }
     const_iterator      end() const { return const_iterator(dimension(), reinterpret_cast(endPointer())); }
 
 //Read-write -- Not available, no setT constructor
 
 #//!\name Search
     bool                contains(const QhullPoint &t) const;
     int                 count(const QhullPoint &t) const;
     int                 indexOf(const QhullPoint &t) const;
     int                 lastIndexOf(const QhullPoint &t) const;
 
     // before const_iterator for conversion with comparison operators
     class iterator {
         friend class const_iterator;
 
     private:
         coordT **       i;
         int             point_dimension;
 
     public:
         typedef ptrdiff_t   difference_type;
         typedef std::bidirectional_iterator_tag  iterator_category;
         typedef QhullPoint *pointer;
         typedef QhullPoint &reference;
         typedef QhullPoint  value_type;
 
                         iterator() : i(0), point_dimension(0) {}
                         iterator(int dimension, coordT **c) : i(c), point_dimension(dimension) {}
                         iterator(const iterator &o) : i(o.i), point_dimension(o.point_dimension) {}
         iterator &      operator=(const iterator &o) { i= o.i; point_dimension= o.point_dimension; return *this; }
 
         QhullPoint      operator*() const { return QhullPoint(point_dimension, *i); }
                       //operator->() n/a, value-type
         QhullPoint      operator[](int idx) { return QhullPoint(point_dimension, *(i+idx)); }
         bool            operator==(const iterator &o) const { return i == o.i && point_dimension == o.point_dimension; }
         bool            operator!=(const iterator &o) const { return !operator==(o); }
         bool            operator==(const const_iterator &o) const
         { return i == reinterpret_cast(o).i && point_dimension == reinterpret_cast(o).point_dimension; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
 
         //! Assumes same point set
         int             operator-(const iterator &o) { return (int)(i-o.i); } //WARN64
         bool            operator>(const iterator &o) const { return i>o.i; }
         bool            operator<=(const iterator &o) const { return !operator>(o); }
         bool            operator<(const iterator &o) const { return i=(const iterator &o) const { return !operator<(o); }
         bool            operator>(const const_iterator &o) const
         { return i > reinterpret_cast(o).i; }
         bool            operator<=(const const_iterator &o) const { return !operator>(o); }
         bool            operator<(const const_iterator &o) const
         { return i < reinterpret_cast(o).i; }
         bool            operator>=(const const_iterator &o) const { return !operator<(o); }
 
         iterator &      operator++() { ++i; return *this; }
         iterator        operator++(int) { iterator o= *this; ++i; return o; }
         iterator &      operator--() { --i; return *this; }
         iterator        operator--(int) { iterator o= *this; --i; return o; }
         iterator        operator+(int j) const { return iterator(point_dimension, i+j); }
         iterator        operator-(int j) const { return operator+(-j); }
         iterator &      operator+=(int j) { i += j; return *this; }
         iterator &      operator-=(int j) { i -= j; return *this; }
     };//QhullPointSet::iterator
 
     class const_iterator {
     private:
         coordT **       i;
         int             point_dimension;
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef QhullPoint value_type;
         typedef value_type *pointer;
         typedef value_type &reference;
         typedef ptrdiff_t  difference_type;
 
                         const_iterator() : i(0), point_dimension(0) {}
                         const_iterator(int dimension, coordT **c) : i(c), point_dimension(dimension) {}
                         const_iterator(const const_iterator &o) : i(o.i), point_dimension(o.point_dimension) {}
                         const_iterator(iterator o) : i(o.i), point_dimension(o.point_dimension) {}
         const_iterator &operator=(const const_iterator &o) { i= o.i; point_dimension= o.point_dimension; return *this; }
 
         QhullPoint      operator*() const { return QhullPoint(point_dimension, *i); }
         QhullPoint      operator[](int idx) { return QhullPoint(point_dimension, *(i+idx)); }
                       //operator->() n/a, value-type
         bool            operator==(const const_iterator &o) const { return i == o.i && point_dimension == o.point_dimension; }
         bool            operator!=(const const_iterator &o) const { return !operator==(o); }
 
         //! Assumes same point set
         int             operator-(const const_iterator &o) { return (int)(i-o.i); } //WARN64
         bool            operator>(const const_iterator &o) const { return i>o.i; }
         bool            operator<=(const const_iterator &o) const { return !operator>(o); }
         bool            operator<(const const_iterator &o) const { return i=(const const_iterator &o) const { return !operator<(o); }
 
         const_iterator &operator++() { ++i; return *this; }
         const_iterator  operator++(int) { const_iterator o= *this; ++i; return o; }
         const_iterator &operator--() { --i; return *this; }
         const_iterator  operator--(int) { const_iterator o= *this; --i; return o; }
         const_iterator  operator+(int j) const { return const_iterator(point_dimension, i+j); }
         const_iterator  operator-(int j) const { return operator+(-j); }
         const_iterator &operator+=(int j) { i += j; return *this; }
         const_iterator &operator-=(int j) { i -= j; return *this; }
     };//QhullPointSet::const_iterator
 
 #//!\name IO
     struct PrintIdentifiers{
         const QhullPointSet *point_set;
         const char *    print_message;
         int             run_id;
         PrintIdentifiers(const char *message, const QhullPointSet *s) : point_set(s), print_message(message) {}
     };//PrintIdentifiers
     PrintIdentifiers printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }
 
     struct PrintPointSet{
         const QhullPointSet *point_set;
         const char *    print_message;
         int             run_id;
         PrintPointSet(int qhRunId, const char *message, const QhullPointSet &s) : point_set(&s), print_message(message), run_id(qhRunId) {}
     };//PrintPointSet
     PrintPointSet       print(int qhRunId) const { return PrintPointSet(qhRunId, 0, *this); }
     PrintPointSet       print(int qhRunId, const char *message) const { return PrintPointSet(qhRunId, message, *this); }
 
 };//QhullPointSet
 
 //derived from qiterator.h
 class QhullPointSetIterator { // FIXUP QH11020 define QhullMutablePointSetIterator
     typedef QhullPointSet::const_iterator const_iterator;
     const QhullPointSet *c;
     const_iterator      i;
 
 public:
                         QhullPointSetIterator(const QhullPointSet &container) : c(&container), i(c->constBegin()) {}
     QhullPointSetIterator &operator=(const QhullPointSet &container) { c= &container; i= c->constBegin(); return *this; }
     bool                findNext(const QhullPoint &p);
     bool                findPrevious(const QhullPoint &p);
     bool                hasNext() const { return i != c->constEnd(); }
     bool                hasPrevious() const { return i != c->constBegin(); }
     QhullPoint          next() { return *i++; }
     QhullPoint          peekNext() const { return *i; }
     QhullPoint          peekPrevious() const { const_iterator p= i; return *--p; }
     QhullPoint          previous() { return *--i; }
     void                toBack() { i= c->constEnd(); }
     void                toFront() { i= c->constBegin(); }
 };//QhullPointSetIterator
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet &fs); // Not inline to avoid using statement
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet::PrintIdentifiers &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullPointSet::PrintPointSet &pr);
 
 #endif // QHULLPOINTSET_H
diff --git a/src/libqhullpcpp/QhullPoints.cpp b/src/libqhullpcpp/QhullPoints.cpp
index 8c3106a..56b15aa 100644
--- a/src/libqhullpcpp/QhullPoints.cpp
+++ b/src/libqhullpcpp/QhullPoints.cpp
@@ -1,244 +1,244 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullPoints.cpp#2 $$Change: 1710 $
-** $DateTime: 2014/03/28 22:23:20 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullPoints.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullPoints.h"
 
 #include 
 #include 
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Conversion
 // See qt-qhull.cpp for QList conversion
 
 #ifndef QHULL_NO_STL
 std::vector QhullPoints::
 toStdVector() const
 {
     QhullPointsIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #//Read-only
 
 int QhullPoints::
 extraCoordinatesCount() const
 {
     if(point_dimension>0){
         return (int)((point_end-point_first)%(size_t)point_dimension);
     }
     return 0;
 }//extraCoordinatesCount
 
 bool QhullPoints::
 operator==(const QhullPoints &other) const
 {
     if(point_dimension!=other.point_dimension || (point_end-point_first) != (other.point_end-other.point_first)){
         return false;
     }
     const coordT *c= point_first;
     const coordT *c2= other.point_first;
     while(c=n){
         n= 0;
     }else if(length<0 || idx+length>=n){
         n -= idx;
     }else{
         n -= idx+length;
     }
     return QhullPoints(point_dimension, n*point_dimension, point_first+idx*point_dimension);
 }//mid
 
 QhullPoint QhullPoints::
 value(int idx) const
 {
     QhullPoint p;
     if(idx>=0 && idx=0 && idxconstEnd()){
         if(*i++ == p){
             return true;
         }
     }
     return false;
 }//findNext
 
 bool QhullPointsIterator::
 findPrevious(const QhullPoint &p)
 {
     while(i!=ps->constBegin()){
         if(*--i == p){
             return true;
         }
     }
     return false;
 }//findPrevious
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::QhullPoints;
 using orgQhull::QhullPointsIterator;
 
 ostream &
 operator<<(ostream &os, const QhullPoints &p)
 {
     QhullPointsIterator i(p);
     while(i.hasNext()){
         os << i.next();
     }
     return os;
 }//operator<
 
 namespace orgQhull {
 
 #//!\name Types
     //! coordinate pointer with dimension
     // with const_iterator and iterator
     class QhullPoints;
     //! Java-style iterator
     class QhullPointsIterator;
 
 class QhullPoints {
 
     // QhullPoints consists of pointers into an array of coordinates.
 
 private:
 #//!\name Fields
     coordT *            point_first;
     coordT *            point_end;  // end>=first.  Trailing coordinates ignored
     int                 point_dimension;  // >= 0
 
 public:
 #//!\name Subtypes
     class const_iterator;
     class iterator;
     typedef QhullPoints::const_iterator ConstIterator;
     typedef QhullPoints::iterator Iterator;
 
 #//!\name Construct
                         QhullPoints() : point_first(0), point_end(0), point_dimension(0) {};
                         QhullPoints(int pointDimension) : point_first(0), point_end(0), point_dimension(pointDimension) { QHULL_ASSERT(pointDimension>=0); }
                         QhullPoints(int pointDimension, int coordinateCount2, coordT *c) : point_first(c), point_end(c+coordinateCount2), point_dimension(pointDimension) { QHULL_ASSERT(pointDimension>=0 && coordinateCount2>=0 ); }
                         //Copy constructor copies pointers but not contents.  Needed for return by value and parameter passing.
                         QhullPoints(const QhullPoints &other)  : point_first(other.point_first), point_end(other.point_end), point_dimension(other.point_dimension) {}
                         ~QhullPoints() {}
 
 //disabled since p= p2 is ambiguous (coord* vs coord)
 private:
     QhullPoints &       operator=(const QhullPoints &other) { point_first= other.point_first; point_end= other.point_end; point_dimension= other.point_dimension; return *this; }
 public:
 
 #//!\name Conversion
     const coordT *      constData() const { return coordinates(); }
     // See coordinates()
     coordT *            data() { return coordinates(); }
     const coordT *      data() const { return coordinates(); }
 #ifndef QHULL_NO_STL
     std::vector toStdVector() const;
 #endif //QHULL_NO_STL
 #ifdef QHULL_USES_QT
     QList   toQList() const;
 #endif //QHULL_USES_QT
 
 #//!\name GetSet
     coordT *            coordinates() const { return point_first; }
     int                 coordinateCount() const { return (int)(point_end-point_first); } // WARN64
     int                 count() const { return (int)size(); } // WARN64
     void                defineAs(int pointDimension, int coordinatesCount, coordT *c) { QHULL_ASSERT(pointDimension>=0 && coordinatesCount>=0 && c!=0); point_first= c; point_end= c+coordinatesCount; point_dimension= pointDimension; }
     void                defineAs(int coordinatesCount, coordT *c) { QHULL_ASSERT((coordinatesCount>=0 && c!=0) || (c==0 && coordinatesCount==0)); point_first= c; point_end= c+coordinatesCount; }
     void                defineAs(const QhullPoints &other) { point_first= other.point_first; point_end= other.point_end; point_dimension= other.point_dimension; }
     int                 dimension() const { return point_dimension; }
     bool                empty() const { return point_end==point_first; }
     coordT *            extraCoordinates() const { return extraCoordinatesCount() ? (point_end-extraCoordinatesCount()) : 0; }
     int                 extraCoordinatesCount() const { return point_dimension>0 ? (int)((point_end-point_first)%(size_t)point_dimension) : 0; }  // WARN64
     bool                includesCoordinates(const coordT *c) const { return c>=point_first && c=0); point_dimension= pointDimension; }
     size_t              size() const { return (point_dimension ? (point_end-point_first)/point_dimension : 0); }
 
 #//!\name Element access
     //! Can not return references since QhullPoint must be generated
     QhullPoint          at(int idx) const { coordT *p= point_first+idx*point_dimension; QHULL_ASSERT(p(other)); return *this; }
         QhullPoint *    operator->() { return this; }
         // value instead of reference since advancePoint() modifies self
         QhullPoint      operator*() const { return *this; }
         QhullPoint      operator[](int idx) const { QhullPoint n= *this; n.advancePoint(idx); return n; }
         bool            operator==(const iterator &other) const { QHULL_ASSERT(dimension()==other.dimension()); return coordinates()==other.coordinates(); }
         bool            operator!=(const iterator &other) const { return !operator==(other); }
         bool            operator<(const iterator &other) const  { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() < other.coordinates(); }
         bool            operator<=(const iterator &other) const { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() <= other.coordinates(); }
         bool            operator>(const iterator &other) const  { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() > other.coordinates(); }
         bool            operator>=(const iterator &other) const { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() >= other.coordinates(); }
         // reinterpret_cast to break circular dependency
         bool            operator==(const QhullPoints::const_iterator &other) const { QHULL_ASSERT(dimension()==reinterpret_cast(other).dimension()); return coordinates()==reinterpret_cast(other).coordinates(); }
         bool            operator!=(const QhullPoints::const_iterator &other) const { return !operator==(reinterpret_cast(other)); }
         bool            operator<(const QhullPoints::const_iterator &other) const  { QHULL_ASSERT(dimension()==reinterpret_cast(other).dimension()); return coordinates() < reinterpret_cast(other).coordinates(); }
         bool            operator<=(const QhullPoints::const_iterator &other) const { QHULL_ASSERT(dimension()==reinterpret_cast(other).dimension()); return coordinates() <= reinterpret_cast(other).coordinates(); }
         bool            operator>(const QhullPoints::const_iterator &other) const  { QHULL_ASSERT(dimension()==reinterpret_cast(other).dimension()); return coordinates() > reinterpret_cast(other).coordinates(); }
         bool            operator>=(const QhullPoints::const_iterator &other) const { QHULL_ASSERT(dimension()==reinterpret_cast(other).dimension()); return coordinates() >= reinterpret_cast(other).coordinates(); }
         iterator &      operator++() { advancePoint(1); return *this; }
         iterator        operator++(int) { iterator n= *this; operator++(); return iterator(n); }
         iterator &      operator--() { advancePoint(-1); return *this; }
         iterator        operator--(int) { iterator n= *this; operator--(); return iterator(n); }
         iterator &      operator+=(int idx) { advancePoint(idx); return *this; }
         iterator &      operator-=(int idx) { advancePoint(-idx); return *this; }
         iterator        operator+(int idx) const { iterator n= *this; n.advancePoint(idx); return n; }
         iterator        operator-(int idx) const { iterator n= *this; n.advancePoint(-idx); return n; }
         difference_type operator-(iterator other) const { QHULL_ASSERT(dimension()==other.dimension()); return (coordinates()-other.coordinates())/dimension(); }
     };//QhullPoints::iterator
 
 #//!\name QhullPoints::const_iterator -- FIXUP QH11018 const_iterator same as iterator
     class const_iterator : public QhullPoint {
 
     public:
         typedef std::random_access_iterator_tag  iterator_category;
         typedef QhullPoint          value_type;
         typedef const value_type   *pointer;
         typedef const value_type &  reference;
         typedef ptrdiff_t           difference_type;
 
                         const_iterator() : QhullPoint() {}
                         const_iterator(const const_iterator &other) : QhullPoint(*other) {}
                         const_iterator(const QhullPoints::iterator &other) : QhullPoint(*other) {}
         explicit        const_iterator(const QhullPoints &ps) : QhullPoint(ps.dimension(), ps.coordinates()) {}
         explicit        const_iterator(int pointDimension, coordT *c): QhullPoint(pointDimension, c) {}
         const_iterator &operator=(const const_iterator &other) { defineAs(const_cast(other)); return *this; }
         // value/non-const since advancePoint(1), etc. modifies self
         QhullPoint      operator*() const { return *this; }
         QhullPoint *    operator->() { return this; }
         QhullPoint      operator[](int idx) const { QhullPoint n= *this; n.advancePoint(idx); return n; }
         bool            operator==(const const_iterator &other) const { QHULL_ASSERT(dimension()==other.dimension()); return coordinates()==other.coordinates(); }
         bool            operator!=(const const_iterator &other) const { return !operator==(other); }
         bool            operator<(const const_iterator &other) const  { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() < other.coordinates(); }
         bool            operator<=(const const_iterator &other) const { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() <= other.coordinates(); }
         bool            operator>(const const_iterator &other) const  { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() > other.coordinates(); }
         bool            operator>=(const const_iterator &other) const { QHULL_ASSERT(dimension()==other.dimension()); return coordinates() >= other.coordinates(); }
         const_iterator &operator++() { advancePoint(1); return *this; }
         const_iterator  operator++(int) { const_iterator n= *this; operator++(); return const_iterator(n); }
         const_iterator &operator--() { advancePoint(-1); return *this; }
         const_iterator  operator--(int) { const_iterator n= *this; operator--(); return const_iterator(n); }
         const_iterator &operator+=(int idx) { advancePoint(idx); return *this; }
         const_iterator &operator-=(int idx) { advancePoint(-idx); return *this; }
         const_iterator  operator+(int idx) const { const_iterator n= *this; n.advancePoint(idx); return n; }
         const_iterator  operator-(int idx) const { const_iterator n= *this; n.advancePoint(-idx); return n; }
         difference_type operator-(const_iterator other) const { QHULL_ASSERT(dimension()==other.dimension()); return (coordinates()-other.coordinates())/dimension(); }
     };//QhullPoints::const_iterator
 
 #//!\name IO
     struct PrintPoints{
         const QhullPoints  *points;
         const char *    point_message;
         int             run_id;
         bool            with_identifier;
         PrintPoints(int qhRunId, const char *message, bool withIdentifier, const QhullPoints &ps) : points(&ps), point_message(message), run_id(qhRunId), with_identifier(withIdentifier) {}
     };//PrintPoints
     PrintPoints          print() const { return  PrintPoints(UsingLibQhull::NOqhRunId, "", false, *this); }
     PrintPoints          print(int qhRunId) const { return PrintPoints(qhRunId, "", true, *this); }
     PrintPoints          print(int qhRunId, const char *message) const { return PrintPoints(qhRunId, message, false, *this); }
     PrintPoints          printWithIdentifier(int qhRunId, const char *message) const { return PrintPoints(qhRunId, message, true, *this); }
     //FIXUP remove message for print()?
 };//QhullPoints
 
 // can't use QHULL_DECLARE_SEQUENTIAL_ITERATOR because next(),etc would return a reference to a temporary
 class QhullPointsIterator
 {
     typedef QhullPoints::const_iterator const_iterator;
 
 private:
 #//!\name Fields
     const QhullPoints  *ps;
     const_iterator      i;
 
 public:
                         QhullPointsIterator(const QhullPoints &other) : ps(&other), i(ps->constBegin()) {}
     QhullPointsIterator &operator=(const QhullPoints &other) { ps = &other; i = ps->constBegin(); return *this; }
     bool                findNext(const QhullPoint &t);
     bool                findPrevious(const QhullPoint &t);
     bool                hasNext() const { return i != ps->constEnd(); }
     bool                hasPrevious() const { return i != ps->constBegin(); }
     QhullPoint          next() { return *i++; }
     QhullPoint          peekNext() const { return *i; }
     QhullPoint          peekPrevious() const { const_iterator p = i; return *--p; }
     QhullPoint          previous() { return *--i; }
     void                toBack() { i = ps->constEnd(); }
     void                toFront() { i = ps->constBegin(); }
 };//QhullPointsIterator
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &          operator<<(std::ostream &os, const orgQhull::QhullPoints &p);
 std::ostream &          operator<<(std::ostream &os, const orgQhull::QhullPoints::PrintPoints &pr);
 
 #endif // QHULLPOINTS_H
diff --git a/src/libqhullpcpp/QhullQh.cpp b/src/libqhullpcpp/QhullQh.cpp
index 89cb850..74a706a 100644
--- a/src/libqhullpcpp/QhullQh.cpp
+++ b/src/libqhullpcpp/QhullQh.cpp
@@ -1,104 +1,104 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullQh.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullQh.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullQh -- Qhull's global data structure, qhT, as a C++ class
 
 
 
 #include "QhullError.h"
 #include "QhullQh.h"
 #include "QhullStat.h"
 
 #include 
 #include 
 
 using std::cerr;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//Global variables
 
 #//Constructor, destructor, etc.
 
 //! If qh_QHpointer==0, invoke with placement new on qh_qh;
 //! Sets qh_qh and qh_qhstat.  Need to reset before UsingLibQhull.
 //! Derived from qh_new_qhull[user.c]
 QhullQh::
 QhullQh()
 {
     static boolT firstcall = True;
 
     if(firstcall){
         if(qhmem.BUFinit!=0){
             throw QhullError(10017, "Qhull error: qhmem already initialized by another class.");
         }
         qh_meminit(NULL);
         firstcall= False;
     }
     // QhullQh() and UsingLibQhull() are the same
 #if qh_QHpointer
     if(qh_qh){
         if(qh old_qhstat){
             throw QhullError(10041, "Qhull internal error: qh_qh.old_qhstat defined (%x) but qh_qh is active.  qh_qh not restored correctly.", 0, 0, 0.0, qh old_qhstat);
         }
         qh old_qhstat= qh_qhstat;
         qh old_tempstack= qhmem.tempstack;
         qh_qhstat= 0;
         qhmem.tempstack= 0;
     }
     qh_qh= static_cast(this);
 #else
     if(strncmp(qh qhull, "qhull", 5) == 0){
         throw QhullError(10022, "Qhull error: Qhull already initialized as run %d", qh run_id);
     }
 #endif
     // NOerrors -- Does not call qh_errexit()
     qh_initstatistics();
     // NOerrors -- Does not call qh_errexit()
     qh_initqhull_start2(NULL, NULL, qh_FILEstderr);
 }//QhullQh
 
 //! UsingLibQhull must be declared along with QhullQh
 QhullQh::
 ~QhullQh()
 {
 #if qh_QHpointer
     if(!qh_qh){
         QhullError e(10042, "Qhull internal error: qh_qh undefined.  Was ~QhullQh() invoked independent of UsingLibQhull?", qh run_id, 0, 0, qh_qh);
         e.logError();
     }else if(!qh_qhstat){
         QhullError e(10043, "Qhull internal error: qh_qhstat null.  Is another thread running?");
         e.logError();
     }else if(qh_qh!=this){
         QhullError e(10044, "Qhull error: ~QhullQh() invoked independent of UsingLibQhull. qh_qh %x (runId %d) vs. QhullQh.runId %d.", qh run_id, run_id, 0.0, qh_qh);
         e.logError();
     }else{
         qh_freeqhull2(qh_ALL); // sets qh.NOerrexit.  Clears struct *qh_qh including run_id, but not qh_qh itself
     }
 #else
     if(&qh_qh!=this){
         QhullError e(10045, "Qhull error: ~QhullQh() invoked independent of UsingLibQhull. qh_qh %x (runId %d) vs. QhullQh.runId %d.", qh run_id, run_id, 0.0, qh_qh);
         e.logError();
     }else{
         qh_freeqhull2(qh_ALL); // sets qh.NOerrexit.  Clears struct *qh_qh including run_id, but not qh_qh itself
     }
 #endif
 }//~QhullQh
 
 #//Parallel Access
 
 }//namespace orgQhull
 
diff --git a/src/libqhullpcpp/QhullQh.h b/src/libqhullpcpp/QhullQh.h
index 6e560ee..7995996 100644
--- a/src/libqhullpcpp/QhullQh.h
+++ b/src/libqhullpcpp/QhullQh.h
@@ -1,52 +1,52 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullQh.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullQh.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLQH_H
 #define QHULLQH_H
 
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name defined here
     //! QhullQh -- Qhull's global data structure, qhT, as a C++ class
     //! See UsingLibQhull.h for C++/C interface to qhT
     class QhullQh;
 
 class QhullQh : public qhT {
 
 #//!\name Constants
     // Set ignored.  PointSet needs explicit dimension
     // Facet from vertices or ridges.vertices.count
     // Ridge from vertices.count
     // Vertex stored in vertexT?  1->16?
     // QhullPoint needs explicit dimension
 
 #//!\name Fields
     //! No fields       POD type equivalent to qhT.  No data or virtual members
 
 public:
 #//!\name Constructors
     QhullQh();
     ~QhullQh();
 
 private:
     //!disable copy constructor and assignment
                         QhullQh(const QhullQh &);
     QhullQh &           operator=(const QhullQh &);
 
 };//class QhullQh
 
 }//namespace orgQhull
 
 #endif // QHULLQH_H
diff --git a/src/libqhullpcpp/QhullRidge.cpp b/src/libqhullpcpp/QhullRidge.cpp
index bde6bd3..912ba64 100644
--- a/src/libqhullpcpp/QhullRidge.cpp
+++ b/src/libqhullpcpp/QhullRidge.cpp
@@ -1,102 +1,102 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullRidge.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullRidge.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullRidge -- Qhull's ridge structure, ridgeT, as a C++ class
 
 #include "QhullSets.h"
 #include "QhullVertex.h"
 #include "QhullRidge.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//class statics
 ridgeT QhullRidge::
 s_empty_ridge= {0,0,0,0,0,
                 0,0};
 
 #//Constructor, destructor, etc.
 
 #//Accessors
 
 //! Return True if nextRidge3d
 //! Simplicial facets may have incomplete ridgeSets
 //! Does not use qh_qh or qh_errexit()
 bool QhullRidge::
 hasNextRidge3d(const QhullFacet f) const
 {
     vertexT *v= 0;
     ridgeT *ridge= qh_nextridge3d(getRidgeT(), f.getFacetT(), &v);
     return (ridge!=0);
 }//hasNextRidge3d
 
 
 
 //! Return next ridge and optional vertex for a 3d facet and ridge
 //! Does not use qh_qh or qh_errexit()
 QhullRidge QhullRidge::
 nextRidge3d(const QhullFacet f, QhullVertex *nextVertex) const
 {
     vertexT *v= 0;
     ridgeT *ridge= qh_nextridge3d(getRidgeT(), f.getFacetT(), &v);
     if(!ridge){
         throw QhullError(10030, "Qhull error nextRidge3d:  missing next ridge for facet %d ridge %d.  Does facet contain ridge?", f.id(), id());
     }
     if(nextVertex!=0){
         *nextVertex= QhullVertex(v);
     }
     return QhullRidge(ridge);
 }//nextRidge3d
 
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullRidge;
 using orgQhull::QhullVertex;
 using orgQhull::UsingLibQhull;
 
 ostream &
 operator<<(ostream &os, const QhullRidge &r)
 {
     os << r.print(UsingLibQhull::NOqhRunId);
     return os;
 }//<< QhullRidge
 
 //! Duplicate of qh_printridge [io.c]
 //!  if pr.run_id==UsingLibQhull::NOqhRunId, no access to qh [needed for QhullVertex/QhullPoint]
 ostream &
 operator<<(ostream &os, const QhullRidge::PrintRidge &pr)
 {
     QhullRidge r= *pr.ridge;
     os << "     - r" << r.id();
     if(r.getRidgeT()->tested){
         os << " tested";
     }
     if(r.getRidgeT()->nonconvex){
         os << " nonconvex";
     }
     os << endl;
     os << r.vertices().print(pr.run_id, "           vertices:");
     if(r.getRidgeT()->top && r.getRidgeT()->bottom){
         os << "           between f" << r.topFacet().id() << " and f" << r.bottomFacet().id() << endl;
     }else if(r.getRidgeT()->top){
         os << "           top f" << r.topFacet().id() << endl;
     }else if(r.getRidgeT()->bottom){
         os << "           bottom f" << r.bottomFacet().id() << endl;
     }
 
     return os;
 }//<< PrintRidge
diff --git a/src/libqhullpcpp/QhullRidge.h b/src/libqhullpcpp/QhullRidge.h
index 3eb32e2..840ca2b 100644
--- a/src/libqhullpcpp/QhullRidge.h
+++ b/src/libqhullpcpp/QhullRidge.h
@@ -1,110 +1,110 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullRidge.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullRidge.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLRIDGE_H
 #define QHULLRIDGE_H
 
 #include "QhullSet.h"
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 #include "QhullFacet.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name ClassRef
     class QhullVertex;
     class QhullVertexSet;
     class QhullFacet;
 
 #//!\name Types
     //! QhullRidge -- Qhull's ridge structure, ridgeT [libqhull.h], as a C++ class
     class QhullRidge;
     typedef QhullSet  QhullRidgeSet;
     typedef QhullSetIterator  QhullRidgeSetIterator;
 
     // see QhullSets.h for QhullRidgeSet and QhullRidgeSetIterator -- avoids circular references
 
 /************************
 a ridge is hull_dim-1 simplex between two neighboring facets.  If the
 facets are non-simplicial, there may be more than one ridge between
 two facets.  E.G. a 4-d hypercube has two triangles between each pair
 of neighboring facets.
 
 topological information:
     vertices            a set of vertices
     top,bottom          neighboring facets with orientation
 
 geometric information:
     tested              True if ridge is clearly convex
     nonconvex           True if ridge is non-convex
 */
 
 class QhullRidge {
 
 #//!\name Fields
     ridgeT *            qh_ridge;
 
 #//!\name Class objects
     static ridgeT       s_empty_ridge;
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
                         QhullRidge() : qh_ridge(&s_empty_ridge) {}
                         // Creates an alias.  Does not copy QhullRidge.  Needed for return by value and parameter passing
                         QhullRidge(const QhullRidge &o) : qh_ridge(o.qh_ridge) {}
                         // Creates an alias.  Does not copy QhullRidge.  Needed for vector
     QhullRidge &        operator=(const QhullRidge &o) { qh_ridge= o.qh_ridge; return *this; }
                         ~QhullRidge() {}
 
 #//!\name Conversion
                         //Implicit conversion from ridgeT
                         QhullRidge(ridgeT *r) : qh_ridge(r ? r : &s_empty_ridge) {}
     ridgeT *            getRidgeT() const { return qh_ridge; }
 
 #//!\name QhullSet
     ridgeT *            getBaseT() const { return getRidgeT(); }
 
 #//!\name getSet
     QhullFacet          bottomFacet() const { return QhullFacet(qh_ridge->bottom); }
     int                 dimension() const { return QhullSetBase::count(qh_ridge->vertices); }
     int                 id() const { return qh_ridge->id; }
     bool                isDefined() const { return qh_ridge != &s_empty_ridge; }
     bool                operator==(const QhullRidge &o) const { return qh_ridge==o.qh_ridge; }
     bool                operator!=(const QhullRidge &o) const { return !operator==(o); }
     QhullFacet          otherFacet(QhullFacet f) const { return QhullFacet(qh_ridge->top==f.getFacetT() ? qh_ridge->bottom : qh_ridge->top); }
     QhullFacet          topFacet() const { return QhullFacet(qh_ridge->top); }
 
 #//!\name forEach
     bool                hasNextRidge3d(const QhullFacet f) const;
     QhullRidge          nextRidge3d(const QhullFacet f) const { return nextRidge3d(f, 0); }
     QhullRidge          nextRidge3d(const QhullFacet f, QhullVertex *nextVertex) const;
     QhullVertexSet      vertices() const { return QhullVertexSet(qh_ridge->vertices); }
 
 #//!\name IO
 
     struct PrintRidge{
         const QhullRidge *ridge;
         int             run_id;
                         PrintRidge(int qhRunId, const QhullRidge &r) : ridge(&r), run_id(qhRunId) {}
     };//PrintRidge
     PrintRidge          print(int qhRunId) const { return PrintRidge(qhRunId, *this); }
 };//class QhullRidge
 
 }//namespace orgQhull
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullRidge &r); 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullRidge::PrintRidge &pr);
 
 #endif // QHULLRIDGE_H
diff --git a/src/libqhullpcpp/QhullSet.cpp b/src/libqhullpcpp/QhullSet.cpp
index 87990c3..32dbacd 100644
--- a/src/libqhullpcpp/QhullSet.cpp
+++ b/src/libqhullpcpp/QhullSet.cpp
@@ -1,47 +1,47 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullSet.cpp#2 $$Change: 1663 $
-** $DateTime: 2014/01/19 17:59:16 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullSet.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullSet -- Qhull's set structure, setT, as a C++ class
 
 #include "QhullError.h"
 #include "QhullSet.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//static members
 
 setT QhullSetBase::
 s_empty_set;
 
 // Same code for qh_setsize [qset.c] and QhullSetBase::count
 int QhullSetBase::count(const setT *set)
 {
     int size;
     const setelemT *sizep;
 
     if (!set)
         return(0);
     sizep= SETsizeaddr_(set);
     if ((size= sizep->i)) {
         size--;
         if (size > set->maxsize) {
             // FIXUP QH11022 How to add additional output to a error? -- qh_setprint(qhmem.ferr, "set: ", set);
             throw QhullError(10032, "QhullSet internal error: current set size %d is greater than maximum size %d\n",
                 size, set->maxsize);
         }
     }else
         size= set->maxsize;
     return size;
 }
 
 
 }//namespace orgQhull
 
diff --git a/src/libqhullpcpp/QhullSet.h b/src/libqhullpcpp/QhullSet.h
index c49c09a..46da38e 100644
--- a/src/libqhullpcpp/QhullSet.h
+++ b/src/libqhullpcpp/QhullSet.h
@@ -1,358 +1,358 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullSet.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullSet.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QhullSet_H
 #define QhullSet_H
 
 #include "QhullError.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 
 #ifndef QHULL_NO_STL
 #include 
 #endif
 
 #ifdef QHULL_USES_QT
  #include 
 #endif
 
 namespace orgQhull {
 
 #//!\name Type
     class QhullSetBase;  //! Base class for QhullSet
     //! QhullSet -- A read-only wrapper to Qhull's collection class, setT.
     //!  QhullSet is similar to STL's  and Qt's QVector.
     //!  QhullSet is unrelated to STL and Qt's set and map types (e.g., QSet and QMap)
     //!  For STL efficiency, QhullSet caches endPointer()
     //!  T must be a pointer type
     //!  A QhullSet does not own its contents -- erase(), clear(), removeFirst(), removeLast(), pop_back(), pop_front(), fromStdList() not defined
     //!  Qhull's FOREACHelement_() [qset.h] is more efficient than QhullSet.  It uses a NULL terminator instead of an end pointer.  STL requires an end pointer.
     //!  Derived from QhullLinkedList.h and Qt/core/tools/qvector.h
 
     //! QhullSetIterator defined below
     //See: QhullPointSet, QhullLinkedList
 
 class QhullSetBase {
 
 private:
 #//!\name Fields --
     setT *              qh_set;
 
 #//!\name Class objects
     static setT         s_empty_set;  //! Workaround for no setT allocator.  Used if setT* is NULL
 
 public:
 #//!\name Class methods
     static int          count(const setT *set);
     //s may be null
     static bool         isEmpty(const setT *s) { return SETempty_(s); }
 
 
 #//!\name Constructors
                         //! Copy constructor copies the pointer but not the set.  Needed for return by value and parameter passing.
                         QhullSetBase(const QhullSetBase &o) : qh_set(o.qh_set) {}
     explicit            QhullSetBase(setT *s) : qh_set(s ? s : &s_empty_set) {}
                         ~QhullSetBase() {}
 
 private:
                         //!disabled since memory allocation for QhullSet not defined
                         QhullSetBase() {}
                         //!disabled since qs= qs2 is ambiguous (pointer vs. contents)
     QhullSetBase &      operator=(const QhullSetBase &);
 public:
 
 #//!\name Conversions
                         //! Not type-safe since setT may contain any type
     void                defineAs(setT *s) { qh_set= s ? s : &s_empty_set; }
     setT *              getSetT() const { return qh_set; }
     setT **             referenceSetT() { return &qh_set; }
 
 #//!\name Read-only
     int                 count() const { return QhullSetBase::count(qh_set); }
     bool                empty() const { return SETfirst_(qh_set)==0; }
     bool                isEmpty() const { return empty(); }
     size_t              size() const { return count(); }
 
 #//!\name Element
 protected:
     void **             beginPointer() const { return &qh_set->e[0].p; }
     void **             elementPointer(int idx) const { QHULL_ASSERT(idx>=0 && idxmaxsize); return &SETelem_(qh_set, idx); }
                         //! Always points to 0
     void **             endPointer() const { return qh_setendpointer(qh_set); }
 };//QhullSetBase
 
 
 //! set of pointers to baseT, T.getBaseT()
 template 
 class QhullSet : public QhullSetBase {
 
 private:
 #//!\name Fields -- see QhullSetBase
 
 #//!\name Class objects
     static setT         s_empty_set;  //! Workaround for no setT allocator.  Used if setT* is NULL
 
 public:
 #//!\name Subtypes
     typedef T *        iterator;
     typedef const T *  const_iterator;
     typedef typename QhullSet::iterator Iterator;
     typedef typename QhullSet::const_iterator ConstIterator;
 
 #//!\name Class methods
     static int          count(const setT *set);
                         //s may be null
     static bool         isEmpty(const setT *s) { return SETempty_(s); }
 
 #//!\name Constructors
                         //Copy constructor copies pointer but not contents.  Needed for return by value.
                         QhullSet(const QhullSet &o) : QhullSetBase(o) {}
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
     explicit            QhullSet(setT *s) : QhullSetBase(s) { QHULL_ASSERT(sizeof(T)==sizeof(void *)); }
                         ~QhullSet() {}
 
 private:
                         //!Disable default constructor and copy assignment.  See QhullSetBase
                         QhullSet();
     QhullSet &       operator=(const QhullSet &);
 public:
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
     std::vector      toStdVector() const;
 #endif
 #ifdef QHULL_USES_QT
     QList            toQList() const;
 #endif
 
 #//!\name Read-only -- see QhullSetBase for count(), empty(), isEmpty(), size()
     using QhullSetBase::count;
     using QhullSetBase::isEmpty;
     // operator== defined for QhullSets of the same type
     bool                operator==(const QhullSet &other) const { return qh_setequal(getSetT(), other.getSetT()); }
     bool                operator!=(const QhullSet &other) const { return !operator==(other); }
 
 #//!\name Element access
     const T &           at(int idx) const { return operator[](idx); }
     T &                 back() { return last(); }
     T &                 back() const { return last(); }
     //! end element is NULL
     const T *           constData() const { return constBegin(); }
     T *                 data() { return begin(); }
     const T *           data() const { return begin(); }
     T &                 first() { QHULL_ASSERT(!isEmpty()); return *begin(); }
     const T &           first() const { QHULL_ASSERT(!isEmpty()); return *begin(); }
     T &                 front() { return first(); }
     const T &           front() const { return first(); }
     T &                 last() { QHULL_ASSERT(!isEmpty()); return *(end()-1); }
     const T &           last() const {  QHULL_ASSERT(!isEmpty()); return *(end()-1); }
     // mid() not available.  No setT constructor
     T &                 operator[](int idx) { T *n= reinterpret_cast(elementPointer(idx)); QHULL_ASSERT(idx>=0 && n < reinterpret_cast(endPointer())); return *n; }
     const T &           operator[](int idx) const { const T *n= reinterpret_cast(elementPointer(idx)); QHULL_ASSERT(idx>=0 && n < reinterpret_cast(endPointer())); return *n; }
     T &                 second() { return operator[](1); }
     const T &           second() const { return operator[](1); }
     T                   value(int idx) const;
     T                   value(int idx, const T &defaultValue) const;
 
 #//!\name GetSet -- Not available, no setT constructor
 
 #//!\name iterator
     iterator            begin() { return iterator(beginPointer()); }
     const_iterator      begin() const { return const_iterator(beginPointer()); }
     const_iterator      constBegin() const { return const_iterator(beginPointer()); }
     const_iterator      constEnd() const { return const_iterator(endPointer()); }
     iterator            end() { return iterator(endPointer()); }
     const_iterator      end() const { return const_iterator(endPointer()); }
 
 #//!\name Search
     bool                contains(const T &t) const;
     int                 count(const T &t) const;
     int                 indexOf(const T &t) const { /* no qh_qh */ return qh_setindex(getSetT(), t.getBaseT()); }
     int                 lastIndexOf(const T &t) const;
 
 };//class QhullSet
 
 // FIXUP? can't use QHULL_DECLARE_SEQUENTIAL_ITERATOR because it is not a template
 
 template 
 class QhullSetIterator {
 
 #//!\name Subtypes
     typedef typename QhullSet::const_iterator const_iterator;
 
 private:
 #//!\name Fields
     const_iterator      i;
     const_iterator      begin_i;
     const_iterator      end_i;
 
 public:
 #//!\name Constructors
                         QhullSetIterator(const QhullSet &s) : i(s.begin()), begin_i(i), end_i(s.end()) {}
                         QhullSetIterator(const QhullSetIterator &o) : i(o.i), begin_i(o.begin_i), end_i(o.end_i) {}
     QhullSetIterator &operator=(const QhullSetIterator &o) { i= o.i; begin_i= o.begin_i; end_i= o.end_i; return *this; }
 
 #//!\name ReadOnly
     int                 countRemaining() { return (int)(end_i-begin_i); } // WARN64
 
 #//!\name Search
     bool                findNext(const T &t);
     bool                findPrevious(const T &t);
 
 #//!\name Foreach
     bool                hasNext() const { return i != end_i; }
     bool                hasPrevious() const { return i != begin_i; }
     T                   next() { return *i++; }
     T                   peekNext() const { return *i; }
     T                   peekPrevious() const { const_iterator p = i; return *--p; }
     T                   previous() { return *--i; }
     void                toBack() { i = end_i; }
     void                toFront() { i = begin_i; }
 };//class QhullSetIterator
 
 #//!\name Conversion
 
 #ifndef QHULL_NO_STL
 template 
 std::vector QhullSet::
 toStdVector() const
 {
     QhullSetIterator i(*this);
     std::vector vs;
     vs.reserve(i.countRemaining());
     while(i.hasNext()){
         vs.push_back(i.next());
     }
     return vs;
 }//toStdVector
 #endif
 
 #ifdef QHULL_USES_QT
 template 
 QList QhullSet::
 toQList() const
 {
     QhullSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 #endif
 
 #//!\name Element
 
 template 
 T QhullSet::
 value(int idx) const
 {
     // Avoid call to qh_setsize() and assert in elementPointer()
     const T *n= reinterpret_cast(&SETelem_(getSetT(), idx));
     return (idx>=0 && n
 T QhullSet::
 value(int idx, const T &defaultValue) const
 {
     // Avoid call to qh_setsize() and assert in elementPointer()
     const T *n= reinterpret_cast(&SETelem_(getSetT(), idx));
     return (idx>=0 && n
 bool QhullSet::
 contains(const T &t) const
 {
     setT *s= getSetT();
     void *e= t.getBaseT();  // contains() is not inline for better error reporting
     int result= qh_setin(s, e);
     return result!=0;
 }//contains
 
 template 
 int QhullSet::
 count(const T &t) const
 {
     int c= 0;
     const T *i= data();
     const T *e= end();
     while(i
 int QhullSet::
 lastIndexOf(const T &t) const
 {
     const T *b= begin();
     const T *i= end();
     while(--i>=b){
         if(*i==t){
             break;
         }
     }
     return (int)(i-b); // WARN64
 }//lastIndexOf
 
 #//!\name QhullSetIterator
 
 template 
 bool QhullSetIterator::
 findNext(const T &t)
 {
     while(i!=end_i){
         if(*(++i)==t){
             return true;
         }
     }
     return false;
 }//findNext
 
 template 
 bool QhullSetIterator::
 findPrevious(const T &t)
 {
     while(i!=begin_i){
         if(*(--i)==t){
             return true;
         }
     }
     return false;
 }//findPrevious
 
 }//namespace orgQhull
 
 
 #//!\name Global
 
 template 
 std::ostream &
 operator<<(std::ostream &os, const orgQhull::QhullSet &qs)
 {
     const T *i= qs.begin();
     const T *e= qs.end();
     while(i!=e){
         os << *i;
         ++i;
     }
     return os;
 }//operator<<
 
 #endif // QhullSet_H
diff --git a/src/libqhullpcpp/QhullSets.h b/src/libqhullpcpp/QhullSets.h
index 245ebee..f3d7d65 100644
--- a/src/libqhullpcpp/QhullSets.h
+++ b/src/libqhullpcpp/QhullSets.h
@@ -1,27 +1,27 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullSets.h#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullSets.h#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLSETS_H
 #define QHULLSETS_H
 
 #include "QhullSet.h"
 
 namespace orgQhull {
 
     //See: QhullFacetSet.h
     //See: QhullPointSet.h
     //See: QhullVertexSet.h
 
     // Avoid circular references between QhullFacet, QhullRidge, and QhullVertex
     class QhullRidge;
     typedef QhullSet  QhullRidgeSet;
     typedef QhullSetIterator  QhullRidgeSetIterator;
 
 }//namespace orgQhull
 
 #endif // QHULLSETS_H
diff --git a/src/libqhullpcpp/QhullStat.cpp b/src/libqhullpcpp/QhullStat.cpp
index fd11936..68a1326 100644
--- a/src/libqhullpcpp/QhullStat.cpp
+++ b/src/libqhullpcpp/QhullStat.cpp
@@ -1,42 +1,42 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullStat.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullStat.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullStat -- Qhull's global data structure, statT, as a C++ class
 
 
 #include "QhullError.h"
 #include "QhullStat.h"
 
 #include 
 #include 
 
 using std::cerr;
 using std::string;
 using std::vector;
 using std::ostream;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Constructor, destructor, etc.
 
 //! If qh_QHpointer==0, invoke with placement new on qh_stat;
 QhullStat::
 QhullStat()
 {
 }//QhullStat
 
 QhullStat::
 ~QhullStat()
 {
 }//~QhullStat
 
 }//namespace orgQhull
 
diff --git a/src/libqhullpcpp/QhullStat.h b/src/libqhullpcpp/QhullStat.h
index 59422e9..aa94575 100644
--- a/src/libqhullpcpp/QhullStat.h
+++ b/src/libqhullpcpp/QhullStat.h
@@ -1,53 +1,53 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullStat.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullStat.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLSTAT_H
 #define QHULLSTAT_H
 
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name defined here
     //! QhullStat -- Qhull's statistics, qhstatT, as a C++ class
     //! Statistics defined with zzdef_() control Qhull's behavior, summarize its result, and report precision problems.
     class QhullStat;
 
 class QhullStat : public qhstatT {
 
 private:
 #//!\name Fields
     //! No fields       POD type equivalent to qhstatT.  No data or virtual members
 
 public:
 #//!\name Constants
 
 #//!\name class methods
     static void         clearStatistics();
 
 #//!\name constructor, assignment, destructor, invariant
                         QhullStat();
                         ~QhullStat();
 
 private:
     //!disable copy constructor and assignment
                         QhullStat(const QhullStat &);
     QhullStat &         operator=(const QhullStat &);
 public:
 
 #//!\name Access
 };//class QhullStat
 
 }//namespace orgQhull
 
 #endif // QHULLSTAT_H
diff --git a/src/libqhullpcpp/QhullVertex.cpp b/src/libqhullpcpp/QhullVertex.cpp
index 3cd6498..24fdfe3 100644
--- a/src/libqhullpcpp/QhullVertex.cpp
+++ b/src/libqhullpcpp/QhullVertex.cpp
@@ -1,94 +1,94 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullVertex.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullVertex.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullVertex -- Qhull's vertex structure, vertexT, as a C++ class
 
 #include "UsingLibQhull.h"
 #include "QhullPoint.h"
 #include "QhullFacetSet.h"
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 #include "QhullFacet.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  // interaction between '_setjmp' and C++ object destruction is non-portable
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//class statics
 vertexT QhullVertex::
 s_empty_vertex= {0,0,0,0,0,
                  0,0,0,0,0,
                  0,0};
 
 #//ForEach
 
 //! Return neighboring facets for a vertex
 //! If neither merging nor Voronoi diagram, requires Qhull::defineVertexNeighborFacets() beforehand.
 QhullFacetSet QhullVertex::
 neighborFacets() const
 {
     if(!neighborFacetsDefined()){
         throw QhullError(10034, "Qhull error: neighboring facets of vertex %d not defined.  Please call Qhull::defineVertexNeighborFacets() beforehand.", id());
     }
     return QhullFacetSet(qh_vertex->neighbors);
 }//neighborFacets
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 using std::string;
 using std::vector;
 using orgQhull::QhullPoint;
 using orgQhull::QhullFacet;
 using orgQhull::QhullFacetSet;
 using orgQhull::QhullFacetSetIterator;
 using orgQhull::QhullVertex;
 using orgQhull::UsingLibQhull;
 
 //! Duplicate of qh_printvertex [io.c]
 ostream &
 operator<<(ostream &os, const QhullVertex::PrintVertex &pr)
 {
     QhullVertex v= *pr.vertex;
     QhullPoint p= v.point();
     os << "- p" << p.id(pr.run_id) << " (v" << v.id() << "): ";
     const realT *c= p.coordinates();
     for(int k= p.dimension(); k--; ){
         os << " " << *c++; // FIXUP QH11010 %5.2g
     }
     if(v.getVertexT()->deleted){
         os << " deleted";
     }
     if(v.getVertexT()->delridge){
         os << " ridgedeleted";
     }
     os << endl;
     if(v.neighborFacetsDefined()){
         QhullFacetSetIterator i= v.neighborFacets();
         if(i.hasNext()){
             os << " neighborFacets:";
             int count= 0;
             while(i.hasNext()){
                 if(++count % 100 == 0){
                     os << endl << "     ";
                 }
                 QhullFacet f= i.next();
                 os << " f" << f.id();
             }
             os << endl;
         }
     }
     return os;
 }//<< PrintVertex
 
diff --git a/src/libqhullpcpp/QhullVertex.h b/src/libqhullpcpp/QhullVertex.h
index e8b0d94..5b88566 100644
--- a/src/libqhullpcpp/QhullVertex.h
+++ b/src/libqhullpcpp/QhullVertex.h
@@ -1,101 +1,101 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullVertex.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullVertex.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHULLVERTEX_H
 #define QHULLVERTEX_H
 
 #include "UsingLibQhull.h"
 #include "QhullPoint.h"
 #include "QhullLinkedList.h"
 #include "QhullSet.h"
 extern "C" {
     #include "libqhull/qhull_a.h"
 }
 
 #include 
 
 namespace orgQhull {
 
 #//!\name ClassRef
     class QhullFacetSet;
 
 #//!\name Types
     //! QhullVertex -- Qhull's vertex structure, vertexT [libqhull.h], as a C++ class
     class QhullVertex;
     typedef QhullLinkedList QhullVertexList;
     typedef QhullLinkedListIterator QhullVertexListIterator;
 
 
 /*********************
   topological information:
     next,previous       doubly-linked list of all vertices
     neighborFacets           set of adjacent facets (only if qh.VERTEXneighbors)
 
   geometric information:
     point               array of DIM coordinates
 */
 
 class QhullVertex {
 
 private:
 #//!\name Fields
     vertexT *           qh_vertex;
 
 #//!\name Class objects
     static vertexT      s_empty_vertex;  // needed for shallow copy
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
                         QhullVertex() : qh_vertex(&s_empty_vertex) {}
                         // Creates an alias.  Does not copy QhullVertex.  Needed for return by value and parameter passing
                         QhullVertex(const QhullVertex &o) : qh_vertex(o.qh_vertex) {}
                         // Creates an alias.  Does not copy QhullVertex.  Needed for vector
     QhullVertex &       operator=(const QhullVertex &o) { qh_vertex= o.qh_vertex; return *this; }
                         ~QhullVertex() {}
 
 #//!\name Conversion
                         //Implicit conversion from vertexT
                         QhullVertex(vertexT *v) : qh_vertex(v ? v : &s_empty_vertex) {}
     vertexT *           getVertexT() const { return qh_vertex; }
     vertexT *           getBaseT() const { return getVertexT(); }
 
 #//!\name getSet
     int                 dimension() const { return (qh_vertex->dim || !isDefined()) ? qh_vertex->dim : UsingLibQhull::globalVertexDimension(); }
     int                 id() const { return qh_vertex->id; }
     bool                isDefined() const { return qh_vertex != &s_empty_vertex; }
                         //! True if defineVertexNeighborFacets() already called.  Auotomatically set for facet merging, Voronoi diagrams
     bool                neighborFacetsDefined() const { return qh_vertex->neighbors != 0; }
     QhullVertex         next() const { return qh_vertex->next; }
     bool                operator==(const QhullVertex &o) const { return qh_vertex==o.qh_vertex; }
     bool                operator!=(const QhullVertex &o) const { return !operator==(o); }
     QhullPoint          point() const { return QhullPoint(dimension(), qh_vertex->point); }
     QhullVertex         previous() const { return qh_vertex->previous; }
 
 #//!\name ForEach
     //See also QhullVertexList
     QhullFacetSet       neighborFacets() const;
 
 #//!\name IO
     struct PrintVertex{
         const QhullVertex *vertex;
         int             run_id;
                         PrintVertex(int qhRunId, const QhullVertex &v) : vertex(&v), run_id(qhRunId) {}
     };//PrintVertex
     PrintVertex         print(int qhRunId) const { return PrintVertex(qhRunId, *this); }
 };//class QhullVertex
 
 }//namespace orgQhull
 
 #//!\name GLobal
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertex::PrintVertex &pr);
 inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertex &v) { os << v.print(orgQhull::UsingLibQhull::NOqhRunId); return os; }
 
 #endif // QHULLVERTEX_H
diff --git a/src/libqhullpcpp/QhullVertexSet.cpp b/src/libqhullpcpp/QhullVertexSet.cpp
index ed46135..09e3365 100644
--- a/src/libqhullpcpp/QhullVertexSet.cpp
+++ b/src/libqhullpcpp/QhullVertexSet.cpp
@@ -1,110 +1,110 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/QhullVertexSet.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/QhullVertexSet.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! QhullVertexSet -- Qhull's linked Vertexs, as a C++ class
 
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 #include "QhullPoint.h"
 #include "QhullRidge.h"
 #include "QhullVertex.h"
 
 using std::string;
 using std::vector;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4611)  /* interaction between '_setjmp' and C++ object destruction is non-portable */
                                     /* setjmp should not be implemented with 'catch' */
 #endif
 
 namespace orgQhull {
 
 QhullVertexSet::
 QhullVertexSet(int qhRunId, facetT *facetlist, setT *facetset, bool allfacets)
 : QhullSet(0)
 , qhsettemp_qhull(0)
 , qhsettemp_defined(false)
 {
     UsingLibQhull q(qhRunId);
     int exitCode = setjmp(qh errexit);
     if(!exitCode){ // no object creation -- destructors skipped on longjmp()
         setT *vertices= qh_facetvertices(facetlist, facetset, allfacets);
         defineAs(vertices);
         qhsettemp_qhull= s_qhull_output;
         qhsettemp_defined= true;
     }
     q.maybeThrowQhullMessage(exitCode);
 }//QhullVertexSet facetlist facetset
 
 void QhullVertexSet::
 freeQhSetTemp()
 {
     if(qhsettemp_defined){
         UsingLibQhull q(qhsettemp_qhull, QhullError::NOthrow);
         if(q.defined()){
             int exitCode = setjmp(qh errexit);
             if(!exitCode){ // no object creation -- destructors skipped on longjmp()
                 qh_settempfree(referenceSetT()); // errors if not top of tempstack or if qhmem corrupted
             }
             q.maybeThrowQhullMessage(exitCode, QhullError::NOthrow);
         }
     }
 }//freeQhSetTemp
 
 QhullVertexSet::
 ~QhullVertexSet()
 {
     freeQhSetTemp();
 }//~QhullVertexSet
 
 }//namespace orgQhull
 
 #//Global functions
 
 using std::endl;
 using std::ostream;
 using orgQhull::QhullPoint;
 using orgQhull::QhullVertex;
 using orgQhull::QhullVertexSet;
 using orgQhull::QhullVertexSetIterator;
 using orgQhull::UsingLibQhull;
 
 //! Print Vertex identifiers to stream.  Space prefix.  From qh_printVertexheader [io.c]
 ostream &
 operator<<(ostream &os, const QhullVertexSet::PrintIdentifiers &pr)
 {
     if(pr.print_message && *pr.print_message){
         os << pr.print_message;
     }
     for(QhullVertexSet::const_iterator i=pr.Vertex_set->begin(); i!=pr.Vertex_set->end(); ++i){
         const QhullVertex v= *i;
         os << " v" << v.id();
     }
     os << endl;
     return os;
 }//<
 
 namespace orgQhull {
 
 #//!\name ClassRef
     class QhullVertex;
 
 #//!\name Types
     //! QhullVertexSet -- a set of Qhull Vertices, as a C++ class.
     //! See Qhull
     class QhullVertexSet;
     typedef QhullSetIterator
                         QhullVertexSetIterator;
 
 class QhullVertexSet : public QhullSet {
 
 private:
 #//!\name Fields
     Qhull *             qhsettemp_qhull; //! For sets allocated with qh_settemp()
     bool                qhsettemp_defined;  //! Set was allocated with q_memalloc()
 
 public:
 #//!\name Constructor
                         //Conversion from setT* is not type-safe.  Implicit conversion for void* to T
    explicit             QhullVertexSet(setT *s) : QhullSet(s), qhsettemp_qhull(0), qhsettemp_defined(false) {}
                         QhullVertexSet(int qhRunId, facetT *facetlist, setT *facetset, bool allfacets);
                         //Copy constructor copies pointer but not contents.  Needed for return by value.
                         QhullVertexSet(const QhullVertexSet &o) : QhullSet(o), qhsettemp_qhull(o.qhsettemp_qhull), qhsettemp_defined(o.qhsettemp_defined) {}
                         ~QhullVertexSet();
 
 private:
                         //!Disable default constructor and copy assignment.  See QhullSetBase
                         QhullVertexSet();
     QhullVertexSet &     operator=(const QhullVertexSet &);
 public:
 
 #//!\name Constructor, destructor
     void                freeQhSetTemp();
 
 #//!\name IO
     struct PrintVertexSet{
         const QhullVertexSet *Vertex_set;
         const char *    print_message;
         int             run_id;
                         PrintVertexSet(int qhRunId, const char *message, const QhullVertexSet *s) : Vertex_set(s), print_message(message), run_id(qhRunId) {}
     };//PrintVertexSet
     const PrintVertexSet       print(int qhRunId, const char *message) const { return PrintVertexSet(qhRunId, message, this); }
 
     struct PrintIdentifiers{
         const QhullVertexSet *Vertex_set;
         const char *    print_message;
                         PrintIdentifiers(const char *message, const QhullVertexSet *s) : Vertex_set(s), print_message(message) {}
     };//PrintIdentifiers
     PrintIdentifiers    printIdentifiers(const char *message) const { return PrintIdentifiers(message, this); }
 
 };//class QhullVertexSet
 
 }//namespace orgQhull
 
 #//!\name Global
 
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet::PrintVertexSet &pr);
 std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet::PrintIdentifiers &p);
 inline std::ostream &operator<<(std::ostream &os, const orgQhull::QhullVertexSet &vs) { os << vs.print(orgQhull::UsingLibQhull::NOqhRunId, ""); return os; }
 
 #endif // QHULLVERTEXSET_H
diff --git a/src/libqhullpcpp/RboxPoints.cpp b/src/libqhullpcpp/RboxPoints.cpp
index 5a248f0..d62f9a3 100644
--- a/src/libqhullpcpp/RboxPoints.cpp
+++ b/src/libqhullpcpp/RboxPoints.cpp
@@ -1,225 +1,225 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/RboxPoints.cpp#2 $$Change: 1710 $
-** $DateTime: 2014/03/28 22:23:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/RboxPoints.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include "QhullError.h"
 #include "RboxPoints.h"
 
 #include 
 
 using std::cerr;
 using std::endl;
 using std::istream;
 using std::ostream;
 using std::ostringstream;
 using std::string;
 using std::vector;
 using std::ws;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #pragma warning( disable : 4996)  // function was declared deprecated(strcpy, localtime, etc.)
 #endif
 
 namespace orgQhull {
 
 #//! RboxPoints -- generate random PointCoordinates for qhull (rbox)
 
 #//Global
 
 //! pointer to RboxPoints for qh_fprintf callback
 RboxPoints *rbox_output= 0;
 
 #//Construct
 RboxPoints::
 RboxPoints()
 : PointCoordinates("rbox")
 , rbox_new_count(0)
 , rbox_status(qh_ERRnone)
 , rbox_message()
 {}
 
 RboxPoints::
 RboxPoints(const char *rboxCommand)
 : PointCoordinates("rbox ")
 , rbox_new_count(0)
 , rbox_status(qh_ERRnone)
 , rbox_message()
 {
     std::string s= comment() + rboxCommand;
     setComment(s);
     appendPoints(rboxCommand);
 }
 
 RboxPoints::
 RboxPoints(const RboxPoints &other)
 : PointCoordinates(other)
 , rbox_new_count(0)
 , rbox_status(other.rbox_status)
 , rbox_message(other.rbox_message)
 {}
 
 RboxPoints & RboxPoints::
 operator=(const RboxPoints &other)
 {
     PointCoordinates::operator=(other);
     rbox_new_count= other.rbox_new_count;
     rbox_status= other.rbox_status;
     rbox_message= other.rbox_message;
     return *this;
 }//operator=
 
 
 RboxPoints::
 ~RboxPoints()
 {}
 
 #//Error
 
 void RboxPoints::
 clearRboxMessage()
 {
     rbox_status= qh_ERRnone;
     rbox_message.clear();
 }//clearRboxMessage
 
 std::string RboxPoints::
 rboxMessage() const
 {
     if(rbox_status!=qh_ERRnone){
         return rbox_message;
     }
     if(isEmpty()){
         return "rbox warning: no points generated\n";
     }
     return "rbox: OK\n";
 }//rboxMessage
 
 int RboxPoints::
 rboxStatus() const
 {
     return rbox_status;
 }
 
 bool RboxPoints::
 hasRboxMessage() const
 {
     return (rbox_status!=qh_ERRnone);
 }
 
 #//Modify
 
 void RboxPoints::
 appendPoints(const char *rboxCommand)
 {
     string s("rbox ");
     s += rboxCommand;
     char *command= const_cast(s.c_str());
     if(rbox_output){
         throw QhullError(10001, "Qhull error: Two simultaneous calls to RboxPoints::appendPoints().  Prevent two processes calling appendPoints() at the same time.  Other RboxPoints '%s'", 0, 0, 0, rbox_output->comment().c_str());
     }
     if(extraCoordinatesCount()!=0){
         throw QhullError(10067, "Qhull error: Extra coordinates (%d) prior to calling RboxPoints::appendPoints.  Was %s", extraCoordinatesCount(), 0, 0.0, comment().c_str());
     }
     int previousCount= count();
     rbox_output= this;              // set rbox_output for qh_fprintf()
     int status= ::qh_rboxpoints(0, 0, command);
     rbox_output= 0;
     if(rbox_status==qh_ERRnone){
         rbox_status= status;
     }
     if(rbox_status!=qh_ERRnone){
         throw QhullError(rbox_status, rbox_message);
     }
     if(extraCoordinatesCount()!=0){
         throw QhullError(10002, "Qhull error: extra coordinates (%d) for PointCoordinates (%x)", extraCoordinatesCount(), 0, 0.0, coordinates());
     }
     if(previousCount+newCount()!=count()){
         throw QhullError(10068, "Qhull error: rbox specified %d points but got %d points for command '%s'", newCount(), count()-previousCount, 0.0, comment().c_str());
     }
 }//appendPoints
 
 }//namespace orgQhull
 
 #//Global functions
 
 /*---------------------------------
 
   qh_fprintf_rbox(fp, msgcode, format, list of args )
     fp is ignored (replaces qh_fprintf_rbox() in userprintf_rbox.c)
     rbox_output == RboxPoints
 
 notes:
     only called from qh_rboxpoints()
     same as fprintf() and Qhull::qh_fprintf()
     fgets() is not trapped like fprintf()
     Do not throw errors from here.  Use qh_errexit_rbox;
 */
 extern "C"
 void qh_fprintf_rbox(FILE*, int msgcode, const char *fmt, ... ) {
     va_list args;
 
     using namespace orgQhull;
 
     if(!qh->rbox_output){
         // No place to write an error message
         qh_errexit_rbox(10072);
     }
     RboxPoints *out= rbox_output;
     va_start(args, fmt);
     if(msgcoderbox_message += newMessage;
         if(out->rbox_statusrbox_status>=MSG_STDERR){
             out->rbox_status= msgcode;
         }
         va_end(args);
         return;
     }
     switch(msgcode){
     case 9391:
     case 9392:
         out->rbox_message += "RboxPoints error: options 'h', 'n' not supported.\n";
         qh_errexit_rbox(10010);
         /* never returns */
     case 9393:
         {
             int dimension= va_arg(args, int);
             string command(va_arg(args, char*));
             int count= va_arg(args, int);
             out->setDimension(dimension);
             out->appendComment(" \"");
             out->appendComment(command.substr(command.find(' ')+1));
             out->appendComment("\"");
             out->setNewCount(count);
             out->reservePoints();
         }
         break;
     case 9407:
         *out << va_arg(args, int);
         // fall through
     case 9405:
         *out << va_arg(args, int);
         // fall through
     case 9403:
         *out << va_arg(args, int);
         break;
     case 9408:
         *out << va_arg(args, double);
         // fall through
     case 9406:
         *out << va_arg(args, double);
         // fall through
     case 9404:
         *out << va_arg(args, double);
         break;
     }
     va_end(args);
 } /* qh_fprintf_rbox */
 
diff --git a/src/libqhullpcpp/RboxPoints.h b/src/libqhullpcpp/RboxPoints.h
index dfe7612..df7ff80 100644
--- a/src/libqhullpcpp/RboxPoints.h
+++ b/src/libqhullpcpp/RboxPoints.h
@@ -1,66 +1,66 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/RboxPoints.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/RboxPoints.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef RBOXPOINTS_H
 #define RBOXPOINTS_H
 
 #include "QhullPoint.h"
 #include "PointCoordinates.h"
 extern "C" {
 #include "libqhull/libqhull.h"
 }
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Types
     //! RboxPoints -- generate random PointCoordinates for Qhull
     class RboxPoints;
 
 class RboxPoints : public PointCoordinates {
 
 private:
 #//!\name Fields and friends
     int                 rbox_new_count;     //! Number of points for PointCoordinates
     int                 rbox_status;    //! error status from rboxpoints.  qh_ERRnone if none.
     std::string         rbox_message;   //! stderr from rboxpoints
 
     friend void ::qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... );
 
 public:
 #//!\name Construct
                         RboxPoints();
     explicit            RboxPoints(const char *rboxCommand);
                         RboxPoints(const RboxPoints &other);
                         RboxPoints &operator=(const RboxPoints &other);
                         ~RboxPoints();
 
 public:
 #//!\name GetSet
     void                clearRboxMessage();
     int                 newCount() const { return rbox_new_count; }
     std::string         rboxMessage() const;
     int                 rboxStatus() const;
     bool                hasRboxMessage() const;
     void                setNewCount(int pointCount) { QHULL_ASSERT(pointCount>=0); rbox_new_count= pointCount; }
 
 #//!\name Modify
     void                appendPoints(const char* rboxCommand);
     using               PointCoordinates::appendPoints;
     void                reservePoints() { reserveCoordinates((count()+newCount())*dimension()); }
 };//class RboxPoints
 
 }//namespace orgQhull
 
 #endif // RBOXPOINTS_H
diff --git a/src/libqhullpcpp/RoadError.cpp b/src/libqhullpcpp/RoadError.cpp
index fd2377f..f54727f 100644
--- a/src/libqhullpcpp/RoadError.cpp
+++ b/src/libqhullpcpp/RoadError.cpp
@@ -1,156 +1,156 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/RoadError.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/RoadError.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! RoadError -- All exceptions thrown by Qhull are RoadErrors
 #//! Do not throw RoadError's from destructors.  Use e.logError() instead.
 
 #include "RoadError.h"
 
 #include 
 #include 
 #include 
 
 using std::cerr;
 using std::cout;
 using std::string;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Class fields
 
 //! Identifies error messages from Qhull and Road for web searches.
 //! See QhullError.h#QHULLlastError and user.h#MSG_ERROR
 const char * RoadError::
 ROADtag= "QH";
 
 std::ostringstream RoadError::
 global_log;
 
 #//Constructor
 
 RoadError::
 RoadError()
 : error_code(0)
 , log_event()
 , error_message()
 { }
 
 RoadError::
 RoadError(const RoadError &other)
 : error_code(other.error_code)
 , log_event(other.log_event)
 , error_message(other.error_message)
 {
 }//copy construct
 
 RoadError::
 RoadError(int code, const std::string &message)
 : error_code(code)
 , log_event(message.c_str())
 , error_message(log_event.toString(ROADtag, error_code))
 {
     log_event.cstr_1= error_message.c_str(); // overwrites initial value
 }
 
 RoadError::
 RoadError(int code, const char *fmt)
 : error_code(code)
 , log_event(fmt)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d)
 : error_code(code)
 , log_event(fmt, d)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2)
 : error_code(code)
 , log_event(fmt, d, d2)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f)
 : error_code(code)
 , log_event(fmt, d, d2, f)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, const char *s)
 : error_code(code)
 , log_event(fmt, d, d2, f, s)
 , error_message(log_event.toString(ROADtag, code)) // char * may go out of scope
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, const void *x)
 : error_code(code)
 , log_event(fmt, d, d2, f, x)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, int i)
 : error_code(code)
 , log_event(fmt, d, d2, f, i)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, long long i)
 : error_code(code)
 , log_event(fmt, d, d2, f, i)
 , error_message()
 { }
 
 RoadError::
 RoadError(int code, const char *fmt, int d, int d2, float f, double e)
 : error_code(code)
 , log_event(fmt, d, d2, f, e)
 , error_message()
 { }
 
 RoadError & RoadError::
 operator=(const RoadError &other)
 {
     error_code= other.error_code;
     error_message= other.error_message;
     log_event= other.log_event;
     return *this;
 }//operator=
 
 #//Virtual
 const char * RoadError::
 what() const throw()
 {
     if(error_message.empty()){
         error_message= log_event.toString(ROADtag, error_code);
     }
     return error_message.c_str();
 }//what
 
 #//Updates
 
 //! Log error instead of throwing it.
 void RoadError::
 logError() const
 {
     global_log << what() << endl;
 }//logError
 
 
 }//namespace orgQhull
 
diff --git a/src/libqhullpcpp/RoadError.h b/src/libqhullpcpp/RoadError.h
index 81ddef2..bbfa508 100644
--- a/src/libqhullpcpp/RoadError.h
+++ b/src/libqhullpcpp/RoadError.h
@@ -1,86 +1,86 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/RoadError.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/RoadError.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef ROADERROR_H
 #define ROADERROR_H
 
 #include "RoadLogEvent.h"
 
 #include 
 #include 
 #include 
 #include 
 
 using std::endl;
 
 namespace orgQhull {
 
 #//!\name Types
     //! RoadError -- Report and log errors
     //!  See discussion in Saylan, G., "Practical C++ error handling in hybrid environments," Dr. Dobb's Journal, p. 50-55, March 2007.
     //!   He uses an auto_ptr to track a stringstream.  It constructs a string on the fly.  RoadError uses the copy constructor to transform RoadLogEvent into a string
     class RoadError;
 
 class RoadError : public std::exception {
 
 private:
 #//!\name Fields
     int                 error_code;  //! Non-zero code (not logged), maybe returned as program status
     RoadLogEvent        log_event;   //! Format string w/ arguments
     mutable std::string error_message;  //! Formated error message.  Must be after log_event.
 
 #//!\name Class fields
     static const char * ROADtag;
     static std::ostringstream  global_log; //! May be replaced with any ostream object
 
 public:
 #//!\name Constants
 
 #//!\name Constructors
     RoadError();
     RoadError(const RoadError &other);  //! Called on throw, generates error_message
     RoadError(int code, const std::string &message);
     RoadError(int code, const char *fmt);
     RoadError(int code, const char *fmt, int d);
     RoadError(int code, const char *fmt, int d, int d2);
     RoadError(int code, const char *fmt, int d, int d2, float f);
     RoadError(int code, const char *fmt, int d, int d2, float f, const char *s);
     RoadError(int code, const char *fmt, int d, int d2, float f, const void *x);
     RoadError(int code, const char *fmt, int d, int d2, float f, int i);
     RoadError(int code, const char *fmt, int d, int d2, float f, long long i);
     RoadError(int code, const char *fmt, int d, int d2, float f, double e);
 
     RoadError &         operator=(const RoadError &other);
                         ~RoadError() throw() {};
 
 #//!\name Class methods
 
     static void         clearGlobalLog() { global_log.seekp(0); }
     static bool         emptyGlobalLog() { return global_log.tellp()<=0; }
     static const char  *stringGlobalLog() { return global_log.str().c_str(); }
 
 #//!\name Virtual
     virtual const char *what() const throw();
 
 #//!\name GetSet
     bool                isDefined() const { return log_event.isDefined(); }
     int                 errorCode() const { return error_code; };
    // FIXUP QH11021 should RoadError provide errorMessage().  Currently what()
     RoadLogEvent        roadLogEvent() const { return log_event; };
 
 #//!\name Update
     void                logError() const;
 };//class RoadError
 
 }//namespace orgQhull
 
 #//!\name Global
 
 inline std::ostream &   operator<<(std::ostream &os, const orgQhull::RoadError &e) { return os << e.what(); }
 
 #endif // ROADERROR_H
diff --git a/src/libqhullpcpp/RoadLogEvent.cpp b/src/libqhullpcpp/RoadLogEvent.cpp
index 1c5904f..0847eb3 100644
--- a/src/libqhullpcpp/RoadLogEvent.cpp
+++ b/src/libqhullpcpp/RoadLogEvent.cpp
@@ -1,122 +1,122 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/RoadLogEvent.cpp#1 $$Change: 1652 $
-** $Date: 2014/01/17 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/RoadLogEvent.cpp#2 $$Change: 1810 $
+** $Date: 2015/01/17 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! RoadError -- All exceptions thrown by Qhull are RoadErrors
 
 #include "RoadError.h"
 
 #include 
 #include 
 #include 
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::string;
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//!\name Conversion
 string RoadLogEvent::
 toString(const char *tag, int code) const
 {
     ostringstream os;
     if(tag && code){
         os << tag << code;
         if(format_string){
             os << " ";
         }
     }
     if(!format_string){
         return os.str();
     }
     const char *s= format_string;
     int dCount= 0;  // Count of %d
     int fCount= 0;  // Count of %f
     char extraCode= '\0';
     while(*s){
         if(*s!='%'){
             os << *s++;
         }else{
             char c= *++s;
             s++;
             switch(c){
             case 'd':
                 if(++dCount>2){
                     os << " ERROR_three_%d_in_format ";
                 }else if(dCount==2){
                     os << int_2;
                 }else{
                     os << int_1;
                 }
                 break;
             case 'e':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << double_1;
                 }
                 break;
             case 'f':
                 if(++fCount>1){
                     os << " ERROR_two_%f_in_format ";
                 }else{
                     os << float_1;
                 }
                 break;
             case 'i':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << int64_1;
                 }
                 break;
             case 's':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << cstr_1;
                 }
                 break;
             case 'u':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << "0x" << std::hex << int64_1 << std::dec;
                 }
                 break;
             case 'x':
                 if(firstExtraCode(os, c, &extraCode)){
                     os << void_1;
                 }
                 break;
             case '%':
                 os << c;
                 break;
             default:
                 os << " ERROR_%" << c << "_not_defined_in_format";
                 break;
             }
         }
     }
     if(s[-1]!='\n'){
         os << endl;
     }
     return os.str();
 }//toString
 
 #//Class helpers (static)
 
 //! True if this char is the first extra code
 bool RoadLogEvent::
 firstExtraCode(std::ostream &os, char c, char *extraCode){
     if(*extraCode){
         os << " ERROR_%" << *extraCode << "_and_%" << c << "_in_format ";
         return false;
     }
     *extraCode= c;
     return true;
 }//firstExtraCode
 
 }//namespace orgQhull
 
diff --git a/src/libqhullpcpp/RoadLogEvent.h b/src/libqhullpcpp/RoadLogEvent.h
index 38b4657..1a8fa31 100644
--- a/src/libqhullpcpp/RoadLogEvent.h
+++ b/src/libqhullpcpp/RoadLogEvent.h
@@ -1,77 +1,77 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/RoadLogEvent.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/RoadLogEvent.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef ROADLOGEVENT_H
 #define ROADLOGEVENT_H
 
 #include 
 #include 
 #include 
 
 namespace orgQhull {
 
 #//!\name Types
     //! RoadLogEvent -- Record an event for the RoadLog
     struct RoadLogEvent;
 
 struct RoadLogEvent {
 
 public:
 #//!\name Fields
     const char *    format_string; //! Format string (a literal with format codes, for logging)
     int             int_1;       //! Integer argument (%d, for logging)
     int             int_2;       //! Integer argument (%d, for logging)
     float           float_1;     //! Float argument (%f, for logging)
     union {                      //! One additional argument (for logging)
         const char *cstr_1;      //!   Cstr argument (%s) -- type checked at construct-time
         const void *void_1;      //!   Void* argument (%x) -- Use upper-case codes for object types
         long long   int64_1;     //!   signed int64 (%i).  Ambiguous if unsigned is also defined.
         double      double_1;    //!   Double argument (%e)
     };
 
 #//!\name Constants
 
 #//!\name Constructors
     RoadLogEvent() : format_string(0), int_1(0), int_2(0), float_1(0), int64_1(0) {};
     explicit RoadLogEvent(const char *fmt) : format_string(fmt), int_1(0), int_2(0), float_1(0), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d) : format_string(fmt), int_1(d), int_2(0), float_1(0), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d, int d2) : format_string(fmt), int_1(d), int_2(d2), float_1(0), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(0) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, const char *s) : format_string(fmt), int_1(d), int_2(d2), float_1(f), cstr_1(s) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, const void *x) : format_string(fmt), int_1(d), int_2(d2), float_1(f), void_1(x) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, int i) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(i) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, long long i) : format_string(fmt), int_1(d), int_2(d2), float_1(f), int64_1(i) {};
     RoadLogEvent(const char *fmt, int d, int d2, float f, double g) : format_string(fmt), int_1(d), int_2(d2), float_1(f), double_1(g) {};
     ~RoadLogEvent() {};
     //! Default copy constructor and assignment
 
 #//!\name GetSet
     bool                isDefined() const { return format_string!=0; }
     int                 int1() const { return int_1; };
     int                 int2() const { return int_2; };
     float               float1() const { return float_1; };
     const char *        format() const { return format_string; };
     const char *        cstr1() const { return cstr_1; };
     const void *        void1() const { return void_1; };
     long long           int64() const { return int64_1; };
     double              double1() const { return double_1; };
 
 #//!\name Conversion
 
     std::string        toString(const char* tag, int code) const;
 
 private:
 #//!\name Class helpers
     static bool         firstExtraCode(std::ostream &os, char c, char *extraCode);
 
 
 };//class RoadLogEvent
 
 }//namespace orgQhull
 
 #endif // ROADLOGEVENT_H
diff --git a/src/libqhullpcpp/UsingLibQhull.cpp b/src/libqhullpcpp/UsingLibQhull.cpp
index f99b15f..7476c98 100644
--- a/src/libqhullpcpp/UsingLibQhull.cpp
+++ b/src/libqhullpcpp/UsingLibQhull.cpp
@@ -1,375 +1,375 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/UsingLibQhull.cpp#2 $$Change: 1711 $
-** $DateTime: 2014/03/30 12:48:17 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/UsingLibQhull.cpp#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #//! UsingLibQhull -- Set up qhull C code from C++
 
 #include "Qhull.h"
 #include "UsingLibQhull.h"
 #include "QhullError.h"
 #include "QhullQh.h"
 
 #ifdef _MSC_VER  // Microsoft Visual C++ -- warning level 4
 #endif
 
 namespace orgQhull {
 
 #//Class objects
 
 const double UsingLibQhull::
 DEFAULTdistanceEpsilon= 1e-15*FACTORepsilon; //! ~DISTround*FACTORepsilon for unit cube
 
 const double UsingLibQhull::
 DEFAULTangleEpsilon= 1e-15*FACTORepsilon; //! ~ANGLEround*FACTORepsilon for unit cube
 
     //! Global pointer to Qhull for qh_fprintf callback and QhullError
 Qhull *
 s_qhull_output= 0;
 
 double UsingLibQhull::
 s_angle_epsilon= 0;
 
 double UsingLibQhull::
 s_distance_epsilon= 0;
 
 //! For QhullPoint.id() w/o qhRunId.  Initialized by Qhull
 const coordT *UsingLibQhull::
 s_points_begin= 0;
 const coordT *UsingLibQhull::
 s_points_end= 0;
 int UsingLibQhull::
 s_points_dimension= 0;
 
 int UsingLibQhull::
 s_vertex_dimension= 0;  // FIXUP QH11023: s_vertex_dimension is required if dimension>15.  Cannot store in QhullVertex
 
 bool UsingLibQhull::
 s_has_points= false;
 
 bool UsingLibQhull::
 s_has_angle_epsilon= false;
 
 bool UsingLibQhull::
 s_has_vertex_dimension= false;
 
 bool UsingLibQhull::
 s_has_distance_epsilon= false;
 
 bool UsingLibQhull::
 s_using_libqhull= false;
 
 #//Constructors
 
 //! Grabs global state (qh_qh, qh_qhstat, qhmem.tempstack)
 //! Follow immediately with setjmp(qh errexit), otherwise errors in libqhull are not caught properly
 //! See qh_restore_qhull [global.c]
 UsingLibQhull::
 UsingLibQhull(Qhull *q)
 : my_qhull(q)
 , qh_exitcode(0)
 {
     checkUsingLibQhull();
     QhullQh *qhullqh= q->qhullQh();
     if(!qhullqh){
         throw QhullError(10014, "Qhull internal error: Qhull.qhullQh() not defined. initializeQhull() not called.");
     }
     if(qhullqh->run_id != q->qhull_run_id){
         throw QhullError(10015, "Qhull error: QhullQh.runId %d != Qhull.runId %d.  Overwritten?", qhullqh->run_id, q->qhull_run_id);
     }
     // qh.old_qhstat is zero at initialization
     // qh.old_tempstack is zero when empty
     // QhullQh() and UsingLibQhull() are the same
 #if qh_QHpointer
     if(qh_qh){
         qh old_qhstat= qh_qhstat;
         qh old_tempstack= qhmem.tempstack;
     }
     qh_qh= qhullqh;
     qh_qhstat= qhullqh->old_qhstat;
     qhmem.tempstack= qhullqh->old_tempstack;
     qhullqh->old_qhstat= 0;
     qhullqh->old_tempstack= 0;
 #else
     #error FIXUP QH11024 static qh_qh not tested.  Delete the line to try.
     if(qhullqh!=&qh_qh){
         throw QhullError(10040, "Qhull internal error: Qhull.qhullQh() is not qh_qh (%x, static).  Overwrite?", 0,0,0.0, &qh_qh);
     }
 #endif
     s_qhull_output= q;      // set s_qhull_output for qh_fprintf()
     qh NOerrexit= False;   // assumes setjmp called next
 }//UsingLibQhull qhull
 
 //! Same as UsingLibQhull but does not throw exceptions
 //! !defined() on failure.  For use in destructors
 UsingLibQhull::
 UsingLibQhull(Qhull *q, int noThrow)
 : my_qhull(0)  // Fail by default
 , qh_exitcode(0)
 {
     QHULL_UNUSED(noThrow);
 
     QhullQh *qhullqh= q->qhullQh();
     if(s_using_libqhull){
         QhullError e(10050, "Qhull error: UsingLibQhull already in use");
         e.logError();
     }else if(!qhullqh || qhullqh->run_id != q->qhull_run_id){
         QhullError e(10051, "Qhull error: Qhull.qhullQh (%x) undefined or QhullQh.runId %d != Qhull.runId %d.  Overwritten?", (qhullqh ? qhullqh->run_id : -1), q->qhull_run_id, 0.0, qhullqh);
         e.logError();
     }else{
         // qh.old_qhstat is zero at initialization
         // qh.old_tempstack is zero when empty
         // QhullQh() and UsingLibQhull() are the same
 #if qh_QHpointer
         if(qh_qh){
             qh old_qhstat= qh_qhstat;
             qh old_tempstack= qhmem.tempstack;
         }
         qh_qh= qhullqh;
         qh_qhstat= qhullqh->old_qhstat;
         qhmem.tempstack= qhullqh->old_tempstack;
         qhullqh->old_qhstat= 0;
         qhullqh->old_tempstack= 0;
 #endif
         my_qhull= q;
         s_qhull_output= q;          // set s_qhull_output for qh_fprintf()
         qh NOerrexit= False;   // assumes setjmp called next
     }
 }//UsingLibQhull qhull noThrow
 
 //! Reuses current global state (qh_qh) from prior UsingQhull
 //! Errors if runId is not the same
 UsingLibQhull::
 UsingLibQhull(int qhRunId)
 : my_qhull(0)
 , qh_exitcode(0)
 {
     checkUsingLibQhull();
 #if qh_QHpointer
     if(!qh_qh || !qh_qhstat){
         throw QhullError(10024, "Qhull error: UsingLibQhull is not active (qh_qh %x or qh_qhstat is not defined)", 0,0,0.0, qh_qh);
     }
 #endif
     if(qh run_id!=qhRunId){
         throw QhullError(10036, "Qhull error: qhRunId %d != qh_qh.runId %d.  Is another Qhull active?", qhRunId, qh run_id);
     }
     if(!s_qhull_output){
         throw QhullError(10037, "Qhull error: UsingLibQhull not active(s_qhull_output undefined).  Invoke UsingLibQhull before this call");
     }
     if(s_qhull_output->qhull_run_id!=qhRunId){
         throw QhullError(10046, "Qhull error: qhRunId %d != s_qhull_output.runId %d.  Is another Qhull active", qhRunId, s_qhull_output->qhull_run_id);
     }
     my_qhull= s_qhull_output;
     qh NOerrexit= False;   // assumes setjmp called next
 }//UsingLibQhull runId
 
 //Leaves libqhull active for runId access
 UsingLibQhull::
 ~UsingLibQhull()
 {
     QhullError e= checkRunId();
     if(e.isDefined()){
         e.logError();
     }else{
 #if qh_QHpointer
         if(qh_qh){
             qh NOerrexit= true;
         }
 #else
         qh NOerrexit= true;
 #endif
     }
     s_using_libqhull= false;
 }//~UsingLibQhull
 
 #//Class methods
 
 void UsingLibQhull::
 checkQhullMemoryEmpty()
 {
     int curlong, totlong, curshort, totshort, maxlong, totbuffer;
     // qh_memtotal does not error
     qh_memtotal(&curlong, &totlong, &curshort, &totshort, &maxlong, &totbuffer);
     if (curlong || totlong){
         throw QhullError(10026, "Qhull error: qhull did not free %d bytes of long memory (%d pieces).", totlong, curlong);
     }
     if (curshort || totshort){
         throw QhullError(10035, "Qhull error: qhull did not free %d bytes of short memory (%d pieces).", totshort, curshort);
     }
 }//checkQhullMemoryEmpty
 
 //! Epsilon for distance to hyperplane angle equality
 double UsingLibQhull::
 currentAngleEpsilon()
 {
     if(s_qhull_output && s_qhull_output->initialized()){
         return s_qhull_output->qhullQh()->ANGLEround*FACTORepsilon;
     }else if(s_has_angle_epsilon){
         return s_angle_epsilon;
     }
     return UsingLibQhull::DEFAULTangleEpsilon;
 }//currentAngleEpsilon
 
 //! Epsilon for distance to hyperplane
 double UsingLibQhull::
 currentDistanceEpsilon()
 {
     if(s_qhull_output && s_qhull_output->initialized()){
         return s_qhull_output->qhullQh()->DISTround*FACTORepsilon;
     }else if(s_has_distance_epsilon){
         return s_distance_epsilon;
     }
     return UsingLibQhull::DEFAULTdistanceEpsilon;
 }//currentDistanceEpsilon
 
 const coordT *UsingLibQhull::
 currentPoints(int *dimension, const coordT **pointsEnd)
 {
     if(s_qhull_output && s_qhull_output->initialized()){
         *dimension= qh hull_dim;
         *pointsEnd= qh first_point+qh num_points*qh hull_dim;
         return qh first_point;
     }else if(s_has_points){
         *dimension= s_points_dimension;
         *pointsEnd= s_points_end;
         return s_points_begin;
     }
     throw QhullError(10059, "Qhull error: missing definition for currentPoints().  Need currentQhull() or setGlobalDistanceEpsilon()");
 }//currentPoints
 
 Qhull &UsingLibQhull::
 currentQhull()
 {
     if(!s_qhull_output){
         throw QhullError(10055, "Qhull error: currentQhull not defined.  Run qhull first.");
     }
     return *s_qhull_output;
 }//currentQhull
 
 // for QhullVertex::dimension() when >= 16
 int UsingLibQhull::
 currentVertexDimension()
 {
     if(s_qhull_output && s_qhull_output->initialized()){
         return s_qhull_output->dimension();
     }else if(s_has_vertex_dimension){
         return s_vertex_dimension;
     }
     throw QhullError(10057, "Qhull error: missing definition for currentVertexDimension().  Need currentQhull() or setGlobalVertexDimension()");
 }//currentVertexDimension
 
 const coordT *UsingLibQhull::
 globalPoints(int *dimension, const coordT **pointsEnd)
 {
     if(s_has_points){
         *dimension= s_points_dimension;
         *pointsEnd= s_points_end;
         return s_points_begin;
     }else{
         return currentPoints(dimension, pointsEnd);
     }
 }//globalPoints
 
 bool UsingLibQhull::
 hasPoints()
 {
     return s_has_points || (s_qhull_output && s_qhull_output->initialized());
 }
 
 bool UsingLibQhull::
 hasVertexDimension()
 {
     return s_has_vertex_dimension || (s_qhull_output && s_qhull_output->initialized());
 }
 
 void UsingLibQhull::
 setGlobals()
 {
     if(s_qhull_output && s_qhull_output->initialized()){
         QhullQh *qqh= s_qhull_output->qhullQh();
         s_angle_epsilon= qqh->ANGLEround*FACTORepsilon;
         s_distance_epsilon= qqh->DISTround*FACTORepsilon;
         s_points_begin= qqh->first_point;
         s_points_dimension= qqh->hull_dim;
         s_points_end= s_points_begin+qqh->num_points*s_points_dimension;
         s_vertex_dimension= qqh->hull_dim;
         s_has_angle_epsilon= true;
         s_has_distance_epsilon= true;
         s_has_points= true;
         s_has_vertex_dimension= true;
     }else{
         throw QhullError(10058, "Qhull error: setGlobals can only be called for currentQhull().  Run qhull first.");
     }
  }//setGlobals
 
 void UsingLibQhull::
 unsetGlobals()
 {
     s_has_angle_epsilon= false;
     s_has_distance_epsilon= false;
     s_has_points= false;
     s_has_vertex_dimension= false;
 }//unsetGlobals
 
 #// Methods
 
 void UsingLibQhull::
 maybeThrowQhullMessage(int exitCode) const
 {
     my_qhull->maybeThrowQhullMessage(exitCode);
     QhullError e= checkRunId(); // Check for qhRunId after libqhull returns. For convenience, ought to be at end of libqhull try block
     if(e.isDefined()){
         throw e;
     }
 }//maybeThrowQhullMessage
 
 void UsingLibQhull::
 maybeThrowQhullMessage(int exitCode, int noThrow) const
 {
     my_qhull->maybeThrowQhullMessage(exitCode, noThrow);
     QhullError e= checkRunId(); // Check for qhRunId after libqhull returns. For convenience, ought to be at end of libqhull try block
     if(e.isDefined()){
         e.logError();
     }
 }//maybeThrowQhullMessage
 
 #//Helpers
 
 //! Return QhullError for maybeThrowFromDestructor()
 QhullError UsingLibQhull::
 checkRunId() const
 {
     // Predeclaring QhullError results in four copy constructors, none used here
 #if qh_QHpointer
     if(qh_qh){ // 0 if ~Qhull
         if(my_qhull->qhull_run_id!=qh run_id){
             return QhullError(10047, "Qhull internal error: Global state (qh_qh, run_id %d) changed.  Should be runId %d.  Another thread?", qh run_id, my_qhull->qhull_run_id);
         }
     }
 #else
     if(qh run_id!=0 && my_qhull->qhull_run_id!=qh run_id){
         return QhullError(10048, "Qhull internal error: Global state (qh_qh, run_id %d) changed.  Should be runId %d.  Another thread?", qh run_id, my_qhull->qhull_run_id);
     }
 #endif
     return QhullError();
 }//checkRunId
 
 //! Can not embed UsingLibQhull.  Otherwise allocated a C++ object missed by qh_errexit
 void UsingLibQhull::
 checkUsingLibQhull() const
 {
     if(s_using_libqhull){
         if(s_qhull_output){
             throw QhullError(10049, "Qhull error: UsingLibQhull already in use by QhullQh.runId %d", s_qhull_output->qhull_run_id);
         }else{
             throw QhullError(10050, "Qhull error: UsingLibQhull already in use.  No s_qhull_output");
         }
     }
     s_using_libqhull= true;
 }//checkUsingLibQhull
 
 }//namespace orgQhull
 
diff --git a/src/libqhullpcpp/UsingLibQhull.h b/src/libqhullpcpp/UsingLibQhull.h
index cc91995..6bf2b49 100644
--- a/src/libqhullpcpp/UsingLibQhull.h
+++ b/src/libqhullpcpp/UsingLibQhull.h
@@ -1,144 +1,144 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/UsingLibQhull.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/UsingLibQhull.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef USINGlibqhull_H
 #define USINGlibqhull_H
 
 #include "QhullError.h"
 extern "C" {
 #include "libqhull/libqhull.h"
 }
 
 namespace orgQhull {
 
 #//!\name Types
     //! UsingLibQhull -- Interface into libqhull and its 'qh' and 'qhstat' macros
     //! Always use with setjmp() for libqhull error handling.
 
 /*******************************
 
 UsingLibQhull is stack based, but as a call
 Qhull declarations are stack-based.  But can't define a
 setjmp environment, since the target goes away.  So must be UsingLibQhull, but can only have one
 setjmp at a time? Can embedded another Using as long as save/restore
 longjmp on exit.
 */
     class UsingLibQhull;
 
     // Defined elsewhere
     class Qhull;
 
 #//!\name  Global variables
 extern Qhull *          s_qhull_output; //! Provide qh_fprintf (Qhull.cpp) access to Qhull
 
 class UsingLibQhull {
 
 private:
 #//!\name Fields
     Qhull *             my_qhull;
     int                 qh_exitcode;
 
 #//!\name Class globals
     //! Global flags
     static bool         s_using_libqhull; //! True if UsingLibQhull is in scope
 
     //! Use global values if s_has_... is set
     static bool         s_has_angle_epsilon; //! True if s_angle_epsilon defined
     static bool         s_has_distance_epsilon; //! True if s_distance_epsilon defined
     static bool         s_has_points;        //! If False (default), Qhull() runs setPointBase()
     static bool         s_has_vertex_dimension; //! True if s_vertex_dimension defined
 
     //! Global values
     static double       s_angle_epsilon;   //! Epsilon for angle equality
     static double       s_distance_epsilon;   //! Epsilon for distance equality
     static const coordT *s_points_begin;            //! For QhullPoint::id() w/o qhRunId.
     static const coordT *s_points_end;            //! For QhullPoint::id() w/o qhRunId.
     static int          s_points_dimension;
     static int          s_vertex_dimension; //! Default dimension (e.g., if Vertex::dimension() >= 16)
 
 public:
 #//!\name Class constants
     static const int    NOqhRunId= 0;   //! qh_qh is not available
     static const int    NOthrow= 1;     //! Do not throw from maybeThrowQhullMessage
     static const int    FACTORepsilon= 10;  //!
     static const double DEFAULTdistanceEpsilon; //! ~DISTround*FACTORepsilon for unit cube
     static const double DEFAULTangleEpsilon;    //! ~ANGLEround*FACTORepsilon for unit cube
 
 #//!\name Class members
     static void         checkQhullMemoryEmpty();
     static double       currentAngleEpsilon();
     static double       currentDistanceEpsilon();
     static const coordT *currentPoints(int *dimension, const coordT **pointsEnd);
     static Qhull &      currentQhull();
     static int          currentVertexDimension();
     static double       globalAngleEpsilon() { return s_has_angle_epsilon ? s_angle_epsilon : currentAngleEpsilon(); }
     static double       globalDistanceEpsilon() { return s_has_distance_epsilon ? s_distance_epsilon : currentDistanceEpsilon(); }
     static double       globalMachineEpsilon() { return REALepsilon; }
     static const coordT *globalPoints(int *dimension, const coordT **pointsEnd);
     static int          globalVertexDimension() { return s_has_vertex_dimension ? s_vertex_dimension : currentVertexDimension(); }
     static bool         hasPoints();        // inline would require Qhull.h
     static bool         hasVertexDimension();
     static void         setGlobalAngleEpsilon(double d) { s_angle_epsilon=d; s_has_angle_epsilon= true; }
     static void         setGlobalDistanceEpsilon(double d) { s_distance_epsilon= d; s_has_distance_epsilon= true; }
     static void         setGlobalPoints(int dimension, const coordT *pointsBegin, const coordT *pointsEnd) { s_points_dimension= dimension; s_points_begin= pointsBegin; s_points_end= pointsEnd; s_has_points= true; }
     static void         setGlobalVertexDimension(int i) { s_vertex_dimension= i; s_has_vertex_dimension= true; }
     static void         setGlobals();
     static void         unsetGlobalAngleEpsilon() { s_has_angle_epsilon= false; }
     static void         unsetGlobalDistanceEpsilon() { s_has_distance_epsilon= false; }
     static void         unsetGlobalPoints() { s_has_points= false; }
     static void         unsetGlobalVertexDimension() { s_has_vertex_dimension= false; }
     static void         unsetGlobals();
 
 #//!\name Constructors
                         UsingLibQhull(Qhull *p);
                         UsingLibQhull(Qhull *p, int noThrow);
                         UsingLibQhull(int qhRunId);
                         ~UsingLibQhull();
 
 private:                //! disable default constructor, copy constructor, and copy assignment
                         UsingLibQhull();
                         UsingLibQhull(const UsingLibQhull &);
    UsingLibQhull &     operator=(const UsingLibQhull &);
 public:
 
 #//!\name Methods
 #//!\name Access
     bool                defined() const { return my_qhull!=0; }
     void                maybeThrowQhullMessage(int exitCode) const;
     void                maybeThrowQhullMessage(int exitCode, int noThrow) const;
 
 #//!\name Helpers
 private:
    QhullError           checkRunId() const;
    void                 checkUsingLibQhull() const;
 
 /***********************************
 You may use global variables in 'qh' after declaring UsingLibQhull.  For example
 
   UsingLibQhull q(qhRunId);
   // NOerrors -- no calls that throw libqhull errors
   cout << "Delaunay Mode: " << qh DELAUNAY;
 
 To trap errors from libqhull, UsingLibQhull must be followed by
 
 UsingLibQhull q(qhRunId);
 int exitCode = setjmp(qh errexit);
 if(!exitCode){ // no object creation -- destructors skipped on longjmp()
     calls to libqhull
 }
 q.maybeThrowQhullMessage(exitCode);
 
 The call to setjmp() can not be moved to a method.  The stack must be preserved for error exits from libqhull.
 
 */
 
 };//UsingLibQhull
 
 }//namespace orgQhull
 
 #endif // USINGlibqhull_H
diff --git a/src/libqhullpcpp/functionObjects.h b/src/libqhullpcpp/functionObjects.h
index 732a32b..7695467 100644
--- a/src/libqhullpcpp/functionObjects.h
+++ b/src/libqhullpcpp/functionObjects.h
@@ -1,66 +1,66 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/functionObjects.h#2 $$Change: 1675 $
-** $DateTime: 2014/02/01 09:38:20 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/functionObjects.h#3 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef QHFUNCTIONOBJECTS_H
 #define QHFUNCTIONOBJECTS_H
 
 #include 
 #include 
 
 namespace orgQhull {
 #//!\name Type
 
     //! Sum of absolute values of the elements in a container
     class AbsoluteSumOf;
     //! Sum of the elements in a container
     class SumOf;
     //! Sum of squares of the elements in a container
     class SumSquaresOf;
 
 #//!\name Class
 
 //! Absolute sum of the elements in a container
 class AbsoluteSumOf
 {
 private:
     double sum;
 public:
     inline AbsoluteSumOf() : sum(0.0) {}
     inline void operator()(double v) { sum += fabs(v); }
     inline operator double() { return sum; }
 };//AbsoluteSumOf
 
 //! Sum of the elements in a container
 class SumOf
 {
 private:
     double sum;
 public:
     inline SumOf() : sum(0.0) {}
     inline void operator()(double v) { sum += v; }
     inline operator double() { return sum; }
 };//SumOf
 
 
 //! Sum of squares of the elements in a container
 class SumSquaresOf
 {
 private:
     double sum;
 public:
     inline SumSquaresOf() : sum(0.0) {}
     inline void operator()(double v) { sum += v*v; }
     inline operator double() { return sum; }
 };//SumSquaresOf
 
 
 }//orgQhull
 
 
 #endif //QHFUNCTIONOBJECTS_H
 
diff --git a/src/libqhullpcpp/qt-qhull.cpp b/src/libqhullpcpp/qt-qhull.cpp
index c16948e..fae481f 100644
--- a/src/libqhullpcpp/qt-qhull.cpp
+++ b/src/libqhullpcpp/qt-qhull.cpp
@@ -1,129 +1,129 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/libqhullpcpp/qt-qhull.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/libqhullpcpp/qt-qhull.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include 
 #include "RoadTest.h"
 
 #ifndef QHULL_USES_QT
 #define QHULL_USES_QT 1
 #endif
 
 #include "Coordinates.h"
 #include "QhullFacetList.h"
 #include "QhullFacetSet.h"
 #include "QhullHyperplane.h"
 #include "QhullPoint.h"
 #include "QhullPoints.h"
 #include "QhullPointSet.h"
 #include "QhullVertex.h"
 #include "QhullVertexSet.h"
 
 namespace orgQhull {
 
 #//Conversions
 
 QList Coordinates::
 toQList() const
 {
     CoordinatesIterator i(*this);
     QList cs;
     while(i.hasNext()){
         cs.append(i.next());
     }
     return cs;
 }//toQList
 
 QList QhullFacetList::
 toQList() const
 {
     QhullLinkedListIterator i(*this);
     QList vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.append(f);
         }
     }
     return vs;
 }//toQList
 
 //! Same as PrintVertices
 QList QhullFacetList::
 vertices_toQList(int qhRunId) const
 {
     QList vs;
     QhullVertexSet qvs(qhRunId, first().getFacetT(), NULL, isSelectAll());
     for(QhullVertexSet::iterator i=qvs.begin(); i!=qvs.end(); ++i){
         vs.push_back(*i);
     }
     return vs;
 }//vertices_toQList
 
 QList QhullFacetSet::
 toQList() const
 {
     QhullSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.append(f);
         }
     }
     return vs;
 }//toQList
 
 #ifdef QHULL_USES_QT
 QList QhullHyperplane::
 toQList() const
 {
     QhullHyperplaneIterator i(*this);
     QList fs;
     while(i.hasNext()){
         fs.append(i.next());
     }
     fs.append(hyperplane_offset);
     return fs;
 }//toQList
 #endif //QHULL_USES_QT
 
 QList QhullPoint::
 toQList() const
 {
     QhullPointIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 
 QList QhullPoints::
 toQList() const
 {
     QhullPointsIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 
 QList QhullPointSet::
 toQList() const
 {
     QhullPointSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         vs.append(i.next());
     }
     return vs;
 }//toQList
 
 }//orgQhull
 
diff --git a/src/libqhullr/geom2_r.c b/src/libqhullr/geom2_r.c
index 4d9b0d6..871d9be 100644
--- a/src/libqhullr/geom2_r.c
+++ b/src/libqhullr/geom2_r.c
@@ -1,2081 +1,2081 @@
 /*
  ---------------------------------
 
 
    geom2_r.c
    infrequently used geometric routines of qhull
 
    see qh-geom.htm and geom_r.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/geom2_r.c#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/geom2_r.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    frequently used code goes into geom_r.c
 */
 
 #include "qhull_ra.h"
 
 /*================== functions in alphabetic order ============*/
 
 /*---------------------------------
 
   qh_copypoints(qh, points, numpoints, dimension)
     return qh_malloc'd copy of points
 */
 coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension) {
   int size;
   coordT *newpoints;
 
   size= numpoints * dimension * (int)sizeof(coordT);
   if (!(newpoints=(coordT*)qh_malloc((size_t)size))) {
     qh_fprintf(qh, qh->ferr, 6004, "qhull error: insufficient memory to copy %d points\n",
         numpoints);
     qh_errexit(qh, qh_ERRmem, NULL, NULL);
   }
   memcpy((char *)newpoints, (char *)points, (size_t)size);
   return newpoints;
 } /* copypoints */
 
 /*---------------------------------
 
   qh_crossproduct(qh, dim, vecA, vecB, vecC )
     crossproduct of 2 dim vectors
     C= A x B
 
   notes:
     from Glasner, Graphics Gems I, p. 639
     only defined for dim==3
 */
 void qh_crossproduct(qhT *qh, int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
 
   if (dim == 3) {
     vecC[0]=   det2_(vecA[1], vecA[2],
                      vecB[1], vecB[2]);
     vecC[1]= - det2_(vecA[0], vecA[2],
                      vecB[0], vecB[2]);
     vecC[2]=   det2_(vecA[0], vecA[1],
                      vecB[0], vecB[1]);
   }
 } /* vcross */
 
 /*---------------------------------
 
   qh_determinant(qh, rows, dim, nearzero )
     compute signed determinant of a square matrix
     uses qh.NEARzero to test for degenerate matrices
 
   returns:
     determinant
     overwrites rows and the matrix
     if dim == 2 or 3
       nearzero iff determinant < qh->NEARzero[dim-1]
       (!quite correct, not critical)
     if dim >= 4
       nearzero iff diagonal[k] < qh->NEARzero[k]
 */
 realT qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero) {
   realT det=0;
   int i;
   boolT sign= False;
 
   *nearzero= False;
   if (dim < 2) {
     qh_fprintf(qh, qh->ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }else if (dim == 2) {
     det= det2_(rows[0][0], rows[0][1],
                  rows[1][0], rows[1][1]);
     if (fabs_(det) < qh->NEARzero[1])  /* not really correct, what should this be? */
       *nearzero= True;
   }else if (dim == 3) {
     det= det3_(rows[0][0], rows[0][1], rows[0][2],
                  rows[1][0], rows[1][1], rows[1][2],
                  rows[2][0], rows[2][1], rows[2][2]);
     if (fabs_(det) < qh->NEARzero[2])  /* not really correct, what should this be? */
       *nearzero= True;
   }else {
     qh_gausselim(qh, rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok*/
     det= 1.0;
     for (i=dim; i--; )
       det *= (rows[i])[i];
     if (sign)
       det= -det;
   }
   return det;
 } /* determinant */
 
 /*---------------------------------
 
   qh_detjoggle(qh, points, numpoints, dimension )
     determine default max joggle for point array
       as qh_distround * qh_JOGGLEdefault
 
   returns:
     initial value for JOGGLEmax from points and REALepsilon
 
   notes:
     computes DISTround since qh_maxmin not called yet
     if qh->SCALElast, last dimension will be scaled later to MAXwidth
 
     loop duplicated from qh_maxmin
 */
 realT qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension) {
   realT abscoord, distround, joggle, maxcoord, mincoord;
   pointT *point, *pointtemp;
   realT maxabs= -REALmax;
   realT sumabs= 0;
   realT maxwidth= 0;
   int k;
 
   for (k=0; k < dimension; k++) {
     if (qh->SCALElast && k == dimension-1)
       abscoord= maxwidth;
     else if (qh->DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
       abscoord= 2 * maxabs * maxabs;  /* may be low by qh->hull_dim/2 */
     else {
       maxcoord= -REALmax;
       mincoord= REALmax;
       FORALLpoint_(qh, points, numpoints) {
         maximize_(maxcoord, point[k]);
         minimize_(mincoord, point[k]);
       }
       maximize_(maxwidth, maxcoord-mincoord);
       abscoord= fmax_(maxcoord, -mincoord);
     }
     sumabs += abscoord;
     maximize_(maxabs, abscoord);
   } /* for k */
   distround= qh_distround(qh, qh->hull_dim, maxabs, sumabs);
   joggle= distround * qh_JOGGLEdefault;
   maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
   trace2((qh, qh->ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
   return joggle;
 } /* detjoggle */
 
 /*---------------------------------
 
   qh_detroundoff(qh)
     determine maximum roundoff errors from
       REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,
       qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
 
     accounts for qh.SETroundoff, qh.RANDOMdist, qh->MERGEexact
       qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
       qh.postmerge_centrum, qh.MINoutside,
       qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
 
   returns:
     sets qh.DISTround, etc. (see below)
     appends precision constants to qh.qhull_options
 
   see:
     qh_maxmin() for qh.NEARzero
 
   design:
     determine qh.DISTround for distance computations
     determine minimum denominators for qh_divzero
     determine qh.ANGLEround for angle computations
     adjust qh.premerge_cos,... for roundoff error
     determine qh.ONEmerge for maximum error due to a single merge
     determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
       qh.MINoutside, qh.WIDEfacet
     initialize qh.max_vertex and qh.minvertex
 */
 void qh_detroundoff(qhT *qh) {
 
   qh_option(qh, "_max-width", NULL, &qh->MAXwidth);
   if (!qh->SETroundoff) {
     qh->DISTround= qh_distround(qh, qh->hull_dim, qh->MAXabs_coord, qh->MAXsumcoord);
     if (qh->RANDOMdist)
       qh->DISTround += qh->RANDOMfactor * qh->MAXabs_coord;
     qh_option(qh, "Error-roundoff", NULL, &qh->DISTround);
   }
   qh->MINdenom= qh->MINdenom_1 * qh->MAXabs_coord;
   qh->MINdenom_1_2= sqrt(qh->MINdenom_1 * qh->hull_dim) ;  /* if will be normalized */
   qh->MINdenom_2= qh->MINdenom_1_2 * qh->MAXabs_coord;
                                               /* for inner product */
   qh->ANGLEround= 1.01 * qh->hull_dim * REALepsilon;
   if (qh->RANDOMdist)
     qh->ANGLEround += qh->RANDOMfactor;
   if (qh->premerge_cos < REALmax/2) {
     qh->premerge_cos -= qh->ANGLEround;
     if (qh->RANDOMdist)
       qh_option(qh, "Angle-premerge-with-random", NULL, &qh->premerge_cos);
   }
   if (qh->postmerge_cos < REALmax/2) {
     qh->postmerge_cos -= qh->ANGLEround;
     if (qh->RANDOMdist)
       qh_option(qh, "Angle-postmerge-with-random", NULL, &qh->postmerge_cos);
   }
   qh->premerge_centrum += 2 * qh->DISTround;    /*2 for centrum and distplane()*/
   qh->postmerge_centrum += 2 * qh->DISTround;
   if (qh->RANDOMdist && (qh->MERGEexact || qh->PREmerge))
     qh_option(qh, "Centrum-premerge-with-random", NULL, &qh->premerge_centrum);
   if (qh->RANDOMdist && qh->POSTmerge)
     qh_option(qh, "Centrum-postmerge-with-random", NULL, &qh->postmerge_centrum);
   { /* compute ONEmerge, max vertex offset for merging simplicial facets */
     realT maxangle= 1.0, maxrho;
 
     minimize_(maxangle, qh->premerge_cos);
     minimize_(maxangle, qh->postmerge_cos);
     /* max diameter * sin theta + DISTround for vertex to its hyperplane */
     qh->ONEmerge= sqrt((realT)qh->hull_dim) * qh->MAXwidth *
       sqrt(1.0 - maxangle * maxangle) + qh->DISTround;
     maxrho= qh->hull_dim * qh->premerge_centrum + qh->DISTround;
     maximize_(qh->ONEmerge, maxrho);
     maxrho= qh->hull_dim * qh->postmerge_centrum + qh->DISTround;
     maximize_(qh->ONEmerge, maxrho);
     if (qh->MERGING)
       qh_option(qh, "_one-merge", NULL, &qh->ONEmerge);
   }
   qh->NEARinside= qh->ONEmerge * qh_RATIOnearinside; /* only used if qh->KEEPnearinside */
   if (qh->JOGGLEmax < REALmax/2 && (qh->KEEPcoplanar || qh->KEEPinside)) {
     realT maxdist;             /* adjust qh.NEARinside for joggle */
     qh->KEEPnearinside= True;
     maxdist= sqrt((realT)qh->hull_dim) * qh->JOGGLEmax + qh->DISTround;
     maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
     maximize_(qh->NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
   }
   if (qh->KEEPnearinside)
     qh_option(qh, "_near-inside", NULL, &qh->NEARinside);
   if (qh->JOGGLEmax < qh->DISTround) {
     qh_fprintf(qh, qh->ferr, 6006, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
          qh->JOGGLEmax, qh->DISTround);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (qh->MINvisible > REALmax/2) {
     if (!qh->MERGING)
       qh->MINvisible= qh->DISTround;
     else if (qh->hull_dim <= 3)
       qh->MINvisible= qh->premerge_centrum;
     else
       qh->MINvisible= qh_COPLANARratio * qh->premerge_centrum;
     if (qh->APPROXhull && qh->MINvisible > qh->MINoutside)
       qh->MINvisible= qh->MINoutside;
     qh_option(qh, "Visible-distance", NULL, &qh->MINvisible);
   }
   if (qh->MAXcoplanar > REALmax/2) {
     qh->MAXcoplanar= qh->MINvisible;
     qh_option(qh, "U-coplanar-distance", NULL, &qh->MAXcoplanar);
   }
   if (!qh->APPROXhull) {             /* user may specify qh->MINoutside */
     qh->MINoutside= 2 * qh->MINvisible;
     if (qh->premerge_cos < REALmax/2)
       maximize_(qh->MINoutside, (1- qh->premerge_cos) * qh->MAXabs_coord);
     qh_option(qh, "Width-outside", NULL, &qh->MINoutside);
   }
   qh->WIDEfacet= qh->MINoutside;
   maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MAXcoplanar);
   maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MINvisible);
   qh_option(qh, "_wide-facet", NULL, &qh->WIDEfacet);
   if (qh->MINvisible > qh->MINoutside + 3 * REALepsilon
   && !qh->BESToutside && !qh->FORCEoutput)
     qh_fprintf(qh, qh->ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
              qh->MINvisible, qh->MINoutside);
   qh->max_vertex= qh->DISTround;
   qh->min_vertex= -qh->DISTround;
   /* numeric constants reported in printsummary */
 } /* detroundoff */
 
 /*---------------------------------
 
   qh_detsimplex(qh, apex, points, dim, nearzero )
     compute determinant of a simplex with point apex and base points
 
   returns:
      signed determinant and nearzero from qh_determinant
 
   notes:
      uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
 
   design:
     construct qm_matrix by subtracting apex from points
     compute determinate
 */
 realT qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero) {
   pointT *coorda, *coordp, *gmcoord, *point, **pointp;
   coordT **rows;
   int k,  i=0;
   realT det;
 
   zinc_(Zdetsimplex);
   gmcoord= qh->gm_matrix;
   rows= qh->gm_row;
   FOREACHpoint_(points) {
     if (i == dim)
       break;
     rows[i++]= gmcoord;
     coordp= point;
     coorda= apex;
     for (k=dim; k--; )
       *(gmcoord++)= *coordp++ - *coorda++;
   }
   if (i < dim) {
     qh_fprintf(qh, qh->ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
                i, dim);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   det= qh_determinant(qh, rows, dim, nearzero);
   trace2((qh, qh->ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
           det, qh_pointid(qh, apex), dim, *nearzero));
   return det;
 } /* detsimplex */
 
 /*---------------------------------
 
   qh_distnorm(qh, dim, point, normal, offset )
     return distance from point to hyperplane at normal/offset
 
   returns:
     dist
 
   notes:
     dist > 0 if point is outside of hyperplane
 
   see:
     qh_distplane in geom_r.c
 */
 realT qh_distnorm(qhT *qh, int dim, pointT *point, pointT *normal, realT *offsetp) {
   coordT *normalp= normal, *coordp= point;
   realT dist;
   int k;
 
   dist= *offsetp;
   for (k=dim; k--; )
     dist += *(coordp++) * *(normalp++);
   return dist;
 } /* distnorm */
 
 /*---------------------------------
 
   qh_distround(qh, dimension, maxabs, maxsumabs )
     compute maximum round-off error for a distance computation
       to a normalized hyperplane
     maxabs is the maximum absolute value of a coordinate
     maxsumabs is the maximum possible sum of absolute coordinate values
 
   returns:
     max dist round for REALepsilon
 
   notes:
     calculate roundoff error according to
     Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
     use sqrt(dim) since one vector is normalized
       or use maxsumabs since one vector is < 1
 */
 realT qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs) {
   realT maxdistsum, maxround;
 
   maxdistsum= sqrt((realT)dimension) * maxabs;
   minimize_( maxdistsum, maxsumabs);
   maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
               /* adds maxabs for offset */
   trace4((qh, qh->ferr, 4008, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",
                  maxround, maxabs, maxsumabs, maxdistsum));
   return maxround;
 } /* distround */
 
 /*---------------------------------
 
   qh_divzero(qh, numer, denom, mindenom1, zerodiv )
     divide by a number that's nearly zero
     mindenom1= minimum denominator for dividing into 1.0
 
   returns:
     quotient
     sets zerodiv and returns 0.0 if it would overflow
 
   design:
     if numer is nearly zero and abs(numer) < abs(denom)
       return numer/denom
     else if numer is nearly zero
       return 0 and zerodiv
     else if denom/numer non-zero
       return numer/denom
     else
       return 0 and zerodiv
 */
 realT qh_divzero(qhT *qh, realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
   realT temp, numerx, denomx;
 
 
   if (numer < mindenom1 && numer > -mindenom1) {
     numerx= fabs_(numer);
     denomx= fabs_(denom);
     if (numerx < denomx) {
       *zerodiv= False;
       return numer/denom;
     }else {
       *zerodiv= True;
       return 0.0;
     }
   }
   temp= denom/numer;
   if (temp > mindenom1 || temp < -mindenom1) {
     *zerodiv= False;
     return numer/denom;
   }else {
     *zerodiv= True;
     return 0.0;
   }
 } /* divzero */
 
 
 /*---------------------------------
 
   qh_facetarea(qh, facet )
     return area for a facet
 
   notes:
     if non-simplicial,
       uses centrum to triangulate facet and sums the projected areas.
     if (qh->DELAUNAY),
       computes projected area instead for last coordinate
     assumes facet->normal exists
     projecting tricoplanar facets to the hyperplane does not appear to make a difference
 
   design:
     if simplicial
       compute area
     else
       for each ridge
         compute area from centrum to ridge
     negate area if upper Delaunay facet
 */
 realT qh_facetarea(qhT *qh, facetT *facet) {
   vertexT *apex;
   pointT *centrum;
   realT area= 0.0;
   ridgeT *ridge, **ridgep;
 
   if (facet->simplicial) {
     apex= SETfirstt_(facet->vertices, vertexT);
     area= qh_facetarea_simplex(qh, qh->hull_dim, apex->point, facet->vertices,
                     apex, facet->toporient, facet->normal, &facet->offset);
   }else {
     if (qh->CENTERtype == qh_AScentrum)
       centrum= facet->center;
     else
       centrum= qh_getcentrum(qh, facet);
     FOREACHridge_(facet->ridges)
       area += qh_facetarea_simplex(qh, qh->hull_dim, centrum, ridge->vertices,
                  NULL, (boolT)(ridge->top == facet),  facet->normal, &facet->offset);
     if (qh->CENTERtype != qh_AScentrum)
       qh_memfree(qh, centrum, qh->normal_size);
   }
   if (facet->upperdelaunay && qh->DELAUNAY)
     area= -area;  /* the normal should be [0,...,1] */
   trace4((qh, qh->ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
   return area;
 } /* facetarea */
 
 /*---------------------------------
 
   qh_facetarea_simplex(qh, dim, apex, vertices, notvertex, toporient, normal, offset )
     return area for a simplex defined by
       an apex, a base of vertices, an orientation, and a unit normal
     if simplicial or tricoplanar facet,
       notvertex is defined and it is skipped in vertices
 
   returns:
     computes area of simplex projected to plane [normal,offset]
     returns 0 if vertex too far below plane (qh->WIDEfacet)
       vertex can't be apex of tricoplanar facet
 
   notes:
     if (qh->DELAUNAY),
       computes projected area instead for last coordinate
     uses qh->gm_matrix/gm_row and qh->hull_dim
     helper function for qh_facetarea
 
   design:
     if Notvertex
       translate simplex to apex
     else
       project simplex to normal/offset
       translate simplex to apex
     if Delaunay
       set last row/column to 0 with -1 on diagonal
     else
       set last row to Normal
     compute determinate
     scale and flip sign for area
 */
 realT qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,
         vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
   pointT *coorda, *coordp, *gmcoord;
   coordT **rows, *normalp;
   int k,  i=0;
   realT area, dist;
   vertexT *vertex, **vertexp;
   boolT nearzero;
 
   gmcoord= qh->gm_matrix;
   rows= qh->gm_row;
   FOREACHvertex_(vertices) {
     if (vertex == notvertex)
       continue;
     rows[i++]= gmcoord;
     coorda= apex;
     coordp= vertex->point;
     normalp= normal;
     if (notvertex) {
       for (k=dim; k--; )
         *(gmcoord++)= *coordp++ - *coorda++;
     }else {
       dist= *offset;
       for (k=dim; k--; )
         dist += *coordp++ * *normalp++;
       if (dist < -qh->WIDEfacet) {
         zinc_(Znoarea);
         return 0.0;
       }
       coordp= vertex->point;
       normalp= normal;
       for (k=dim; k--; )
         *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
     }
   }
   if (i != dim-1) {
     qh_fprintf(qh, qh->ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
                i, dim);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   rows[i]= gmcoord;
   if (qh->DELAUNAY) {
     for (i=0; i < dim-1; i++)
       rows[i][dim-1]= 0.0;
     for (k=dim; k--; )
       *(gmcoord++)= 0.0;
     rows[dim-1][dim-1]= -1.0;
   }else {
     normalp= normal;
     for (k=dim; k--; )
       *(gmcoord++)= *normalp++;
   }
   zinc_(Zdetsimplex);
   area= qh_determinant(qh, rows, dim, &nearzero);
   if (toporient)
     area= -area;
   area *= qh->AREAfactor;
   trace4((qh, qh->ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
           area, qh_pointid(qh, apex), toporient, nearzero));
   return area;
 } /* facetarea_simplex */
 
 /*---------------------------------
 
   qh_facetcenter(qh, vertices )
     return Voronoi center (Voronoi vertex) for a facet's vertices
 
   returns:
     return temporary point equal to the center
 
   see:
     qh_voronoi_center()
 */
 pointT *qh_facetcenter(qhT *qh, setT *vertices) {
   setT *points= qh_settemp(qh, qh_setsize(qh, vertices));
   vertexT *vertex, **vertexp;
   pointT *center;
 
   FOREACHvertex_(vertices)
     qh_setappend(qh, &points, vertex->point);
   center= qh_voronoi_center(qh, qh->hull_dim-1, points);
   qh_settempfree(qh, &points);
   return center;
 } /* facetcenter */
 
 /*---------------------------------
 
   qh_findgooddist(qh, point, facetA, dist, facetlist )
     find best good facet visible for point from facetA
     assumes facetA is visible from point
 
   returns:
     best facet, i.e., good facet that is furthest from point
       distance to best facet
       NULL if none
 
     moves good, visible facets (and some other visible facets)
       to end of qh->facet_list
 
   notes:
     uses qh->visit_id
 
   design:
     initialize bestfacet if facetA is good
     move facetA to end of facetlist
     for each facet on facetlist
       for each unvisited neighbor of facet
         move visible neighbors to end of facetlist
         update best good neighbor
         if no good neighbors, update best facet
 */
 facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp,
                facetT **facetlist) {
   realT bestdist= -REALmax, dist;
   facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
   boolT goodseen= False;
 
   if (facetA->good) {
     zzinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
     qh_distplane(qh, point, facetA, &bestdist);
     bestfacet= facetA;
     goodseen= True;
   }
   qh_removefacet(qh, facetA);
   qh_appendfacet(qh, facetA);
   *facetlist= facetA;
   facetA->visitid= ++qh->visit_id;
   FORALLfacet_(*facetlist) {
     FOREACHneighbor_(facet) {
       if (neighbor->visitid == qh->visit_id)
         continue;
       neighbor->visitid= qh->visit_id;
       if (goodseen && !neighbor->good)
         continue;
       zzinc_(Zcheckpart);
       qh_distplane(qh, point, neighbor, &dist);
       if (dist > 0) {
         qh_removefacet(qh, neighbor);
         qh_appendfacet(qh, neighbor);
         if (neighbor->good) {
           goodseen= True;
           if (dist > bestdist) {
             bestdist= dist;
             bestfacet= neighbor;
           }
         }
       }
     }
   }
   if (bestfacet) {
     *distp= bestdist;
     trace2((qh, qh->ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
       qh_pointid(qh, point), bestdist, bestfacet->id));
     return bestfacet;
   }
   trace4((qh, qh->ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",
       qh_pointid(qh, point), facetA->id));
   return NULL;
 }  /* findgooddist */
 
 /*---------------------------------
 
   qh_getarea(qh, facetlist )
     set area of all facets in facetlist
     collect statistics
     nop if hasAreaVolume
 
   returns:
     sets qh->totarea/totvol to total area and volume of convex hull
     for Delaunay triangulation, computes projected area of the lower or upper hull
       ignores upper hull if qh->ATinfinity
 
   notes:
     could compute outer volume by expanding facet area by rays from interior
     the following attempt at perpendicular projection underestimated badly:
       qh.totoutvol += (-dist + facet->maxoutside + qh->DISTround)
                             * area/ qh->hull_dim;
   design:
     for each facet on facetlist
       compute facet->area
       update qh.totarea and qh.totvol
 */
 void qh_getarea(qhT *qh, facetT *facetlist) {
   realT area;
   realT dist;
   facetT *facet;
 
   if (qh->hasAreaVolume)
     return;
   if (qh->REPORTfreq)
     qh_fprintf(qh, qh->ferr, 8020, "computing area of each facet and volume of the convex hull\n");
   else
     trace1((qh, qh->ferr, 1001, "qh_getarea: computing volume and area for each facet\n"));
   qh->totarea= qh->totvol= 0.0;
   FORALLfacet_(facetlist) {
     if (!facet->normal)
       continue;
     if (facet->upperdelaunay && qh->ATinfinity)
       continue;
     if (!facet->isarea) {
       facet->f.area= qh_facetarea(qh, facet);
       facet->isarea= True;
     }
     area= facet->f.area;
     if (qh->DELAUNAY) {
       if (facet->upperdelaunay == qh->UPPERdelaunay)
         qh->totarea += area;
     }else {
       qh->totarea += area;
       qh_distplane(qh, qh->interior_point, facet, &dist);
       qh->totvol += -dist * area/ qh->hull_dim;
     }
     if (qh->PRINTstatistics) {
       wadd_(Wareatot, area);
       wmax_(Wareamax, area);
       wmin_(Wareamin, area);
     }
   }
   qh->hasAreaVolume= True;
 } /* getarea */
 
 /*---------------------------------
 
   qh_gram_schmidt(qh, dim, row )
     implements Gram-Schmidt orthogonalization by rows
 
   returns:
     false if zero norm
     overwrites rows[dim][dim]
 
   notes:
     see Golub & van Loan Algorithm 6.2-2
     overflow due to small divisors not handled
 
   design:
     for each row
       compute norm for row
       if non-zero, normalize row
       for each remaining rowA
         compute inner product of row and rowA
         reduce rowA by row * inner product
 */
 boolT qh_gram_schmidt(qhT *qh, int dim, realT **row) {
   realT *rowi, *rowj, norm;
   int i, j, k;
 
   for (i=0; i < dim; i++) {
     rowi= row[i];
     for (norm= 0.0, k= dim; k--; rowi++)
       norm += *rowi * *rowi;
     norm= sqrt(norm);
     wmin_(Wmindenom, norm);
     if (norm == 0.0)  /* either 0 or overflow due to sqrt */
       return False;
     for (k=dim; k--; )
       *(--rowi) /= norm;
     for (j=i+1; j < dim; j++) {
       rowj= row[j];
       for (norm= 0.0, k=dim; k--; )
         norm += *rowi++ * *rowj++;
       for (k=dim; k--; )
         *(--rowj) -= *(--rowi) * norm;
     }
   }
   return True;
 } /* gram_schmidt */
 
 
 /*---------------------------------
 
   qh_inthresholds(qh, normal, angle )
     return True if normal within qh.lower_/upper_threshold
 
   returns:
     estimate of angle by summing of threshold diffs
       angle may be NULL
       smaller "angle" is better
 
   notes:
     invalid if qh.SPLITthresholds
 
   see:
     qh.lower_threshold in qh_initbuild()
     qh_initthresholds()
 
   design:
     for each dimension
       test threshold
 */
 boolT qh_inthresholds(qhT *qh, coordT *normal, realT *angle) {
   boolT within= True;
   int k;
   realT threshold;
 
   if (angle)
     *angle= 0.0;
   for (k=0; k < qh->hull_dim; k++) {
     threshold= qh->lower_threshold[k];
     if (threshold > -REALmax/2) {
       if (normal[k] < threshold)
         within= False;
       if (angle) {
         threshold -= normal[k];
         *angle += fabs_(threshold);
       }
     }
     if (qh->upper_threshold[k] < REALmax/2) {
       threshold= qh->upper_threshold[k];
       if (normal[k] > threshold)
         within= False;
       if (angle) {
         threshold -= normal[k];
         *angle += fabs_(threshold);
       }
     }
   }
   return within;
 } /* inthresholds */
 
 
 /*---------------------------------
 
   qh_joggleinput(qh)
     randomly joggle input to Qhull by qh.JOGGLEmax
     initial input is qh.first_point/qh.num_points of qh.hull_dim
       repeated calls use qh.input_points/qh.num_points
 
   returns:
     joggles points at qh.first_point/qh.num_points
     copies data to qh.input_points/qh.input_malloc if first time
     determines qh.JOGGLEmax if it was zero
     if qh.DELAUNAY
       computes the Delaunay projection of the joggled points
 
   notes:
     if qh.DELAUNAY, unnecessarily joggles the last coordinate
     the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
 
   design:
     if qh.DELAUNAY
       set qh.SCALElast for reduced precision errors
     if first call
       initialize qh.input_points to the original input points
       if qh.JOGGLEmax == 0
         determine default qh.JOGGLEmax
     else
       increase qh.JOGGLEmax according to qh.build_cnt
     joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
     if qh.DELAUNAY
       sets the Delaunay projection
 */
 void qh_joggleinput(qhT *qh) {
   int i, seed, size;
   coordT *coordp, *inputp;
   realT randr, randa, randb;
 
   if (!qh->input_points) { /* first call */
     qh->input_points= qh->first_point;
     qh->input_malloc= qh->POINTSmalloc;
     size= qh->num_points * qh->hull_dim * sizeof(coordT);
     if (!(qh->first_point=(coordT*)qh_malloc((size_t)size))) {
       qh_fprintf(qh, qh->ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",
           qh->num_points);
       qh_errexit(qh, qh_ERRmem, NULL, NULL);
     }
     qh->POINTSmalloc= True;
     if (qh->JOGGLEmax == 0.0) {
       qh->JOGGLEmax= qh_detjoggle(qh, qh->input_points, qh->num_points, qh->hull_dim);
       qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
     }
   }else {                 /* repeated call */
     if (!qh->RERUN && qh->build_cnt > qh_JOGGLEretry) {
       if (((qh->build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
         realT maxjoggle= qh->MAXwidth * qh_JOGGLEmaxincrease;
         if (qh->JOGGLEmax < maxjoggle) {
           qh->JOGGLEmax *= qh_JOGGLEincrease;
           minimize_(qh->JOGGLEmax, maxjoggle);
         }
       }
     }
     qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
   }
   if (qh->build_cnt > 1 && qh->JOGGLEmax > fmax_(qh->MAXwidth/4, 0.1)) {
       qh_fprintf(qh, qh->ferr, 6010, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input.  If possible, recompile Qhull with higher-precision reals.\n",
                 qh->JOGGLEmax);
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   /* for some reason, using qh->ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
   seed= qh_RANDOMint;
   qh_option(qh, "_joggle-seed", &seed, NULL);
   trace0((qh, qh->ferr, 6, "qh_joggleinput: joggle input by %2.2g with seed %d\n",
     qh->JOGGLEmax, seed));
   inputp= qh->input_points;
   coordp= qh->first_point;
   randa= 2.0 * qh->JOGGLEmax/qh_RANDOMmax;
   randb= -qh->JOGGLEmax;
   size= qh->num_points * qh->hull_dim;
   for (i=size; i--; ) {
     randr= qh_RANDOMint;
     *(coordp++)= *(inputp++) + (randr * randa + randb);
   }
   if (qh->DELAUNAY) {
     qh->last_low= qh->last_high= qh->last_newhigh= REALmax;
     qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);
   }
 } /* joggleinput */
 
 /*---------------------------------
 
   qh_maxabsval(qh, normal, dim )
     return pointer to maximum absolute value of a dim vector
     returns NULL if dim=0
 */
 realT *qh_maxabsval(qhT *qh, realT *normal, int dim) {
   realT maxval= -REALmax;
   realT *maxp= NULL, *colp, absval;
   int k;
 
   for (k=dim, colp= normal; k--; colp++) {
     absval= fabs_(*colp);
     if (absval > maxval) {
       maxval= absval;
       maxp= colp;
     }
   }
   return maxp;
 } /* maxabsval */
 
 
 /*---------------------------------
 
   qh_maxmin(qh, points, numpoints, dimension )
     return max/min points for each dimension
     determine max and min coordinates
 
   returns:
     returns a temporary set of max and min points
       may include duplicate points. Does not include qh.GOODpoint
     sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
          qh.MAXlastcoord, qh.MINlastcoord
     initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
 
   notes:
     loop duplicated in qh_detjoggle()
 
   design:
     initialize global precision variables
     checks definition of REAL...
     for each dimension
       for each point
         collect maximum and minimum point
       collect maximum of maximums and minimum of minimums
       determine qh.NEARzero for Gaussian Elimination
 */
 setT *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension) {
   int k;
   realT maxcoord, temp;
   pointT *minimum, *maximum, *point, *pointtemp;
   setT *set;
 
   qh->max_outside= 0.0;
   qh->MAXabs_coord= 0.0;
   qh->MAXwidth= -REALmax;
   qh->MAXsumcoord= 0.0;
   qh->min_vertex= 0.0;
   qh->WAScoplanar= False;
   if (qh->ZEROcentrum)
     qh->ZEROall_ok= True;
   if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
   && REALmax > 0.0 && -REALmax < 0.0)
     ; /* all ok */
   else {
     qh_fprintf(qh, qh->ferr, 6011, "qhull error: floating point constants in user.h are wrong\n\
 REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",
              REALepsilon, REALmin, REALmax, -REALmax);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   set= qh_settemp(qh, 2*dimension);
   for (k=0; k < dimension; k++) {
     if (points == qh->GOODpointp)
       minimum= maximum= points + dimension;
     else
       minimum= maximum= points;
     FORALLpoint_(qh, points, numpoints) {
       if (point == qh->GOODpointp)
         continue;
       if (maximum[k] < point[k])
         maximum= point;
       else if (minimum[k] > point[k])
         minimum= point;
     }
     if (k == dimension-1) {
       qh->MINlastcoord= minimum[k];
       qh->MAXlastcoord= maximum[k];
     }
     if (qh->SCALElast && k == dimension-1)
       maxcoord= qh->MAXwidth;
     else {
       maxcoord= fmax_(maximum[k], -minimum[k]);
       if (qh->GOODpointp) {
         temp= fmax_(qh->GOODpointp[k], -qh->GOODpointp[k]);
         maximize_(maxcoord, temp);
       }
       temp= maximum[k] - minimum[k];
       maximize_(qh->MAXwidth, temp);
     }
     maximize_(qh->MAXabs_coord, maxcoord);
     qh->MAXsumcoord += maxcoord;
     qh_setappend(qh, &set, maximum);
     qh_setappend(qh, &set, minimum);
     /* calculation of qh->NEARzero is based on error formula 4.4-13 of
        Golub & van Loan, authors say n^3 can be ignored and 10 be used in
        place of rho */
     qh->NEARzero[k]= 80 * qh->MAXsumcoord * REALepsilon;
   }
   if (qh->IStracing >=1)
     qh_printpoints(qh, qh->ferr, "qh_maxmin: found the max and min points(by dim):", set);
   return(set);
 } /* maxmin */
 
 /*---------------------------------
 
   qh_maxouter(qh)
     return maximum distance from facet to outer plane
     normally this is qh.max_outside+qh.DISTround
     does not include qh.JOGGLEmax
 
   see:
     qh_outerinner()
 
   notes:
     need to add another qh.DISTround if testing actual point with computation
 
   for joggle:
     qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
     need to use Wnewvertexmax since could have a coplanar point for a high
       facet that is replaced by a low facet
     need to add qh.JOGGLEmax if testing input points
 */
 realT qh_maxouter(qhT *qh) {
   realT dist;
 
   dist= fmax_(qh->max_outside, qh->DISTround);
   dist += qh->DISTround;
   trace4((qh, qh->ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh->max_outside));
   return dist;
 } /* maxouter */
 
 /*---------------------------------
 
   qh_maxsimplex(qh, dim, maxpoints, points, numpoints, simplex )
     determines maximum simplex for a set of points
     starts from points already in simplex
     skips qh.GOODpointp (assumes that it isn't in maxpoints)
 
   returns:
     simplex with dim+1 points
 
   notes:
     assumes at least pointsneeded points in points
     maximizes determinate for x,y,z,w, etc.
     uses maxpoints as long as determinate is clearly non-zero
 
   design:
     initialize simplex with at least two points
       (find points with max or min x coordinate)
     for each remaining dimension
       add point that maximizes the determinate
         (use points from maxpoints first)
 */
 void qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
   pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
   boolT nearzero, maxnearzero= False;
   int k, sizinit;
   realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
 
   sizinit= qh_setsize(qh, *simplex);
   if (sizinit < 2) {
     if (qh_setsize(qh, maxpoints) >= 2) {
       FOREACHpoint_(maxpoints) {
         if (maxcoord < point[0]) {
           maxcoord= point[0];
           maxx= point;
         }
         if (mincoord > point[0]) {
           mincoord= point[0];
           minx= point;
         }
       }
     }else {
       FORALLpoint_(qh, points, numpoints) {
         if (point == qh->GOODpointp)
           continue;
         if (maxcoord < point[0]) {
           maxcoord= point[0];
           maxx= point;
         }
         if (mincoord > point[0]) {
           mincoord= point[0];
           minx= point;
         }
       }
     }
     qh_setunique(qh, simplex, minx);
     if (qh_setsize(qh, *simplex) < 2)
       qh_setunique(qh, simplex, maxx);
     sizinit= qh_setsize(qh, *simplex);
     if (sizinit < 2) {
       qh_precision(qh, "input has same x coordinate");
       if (zzval_(Zsetplane) > qh->hull_dim+1) {
         qh_fprintf(qh, qh->ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",
                  qh_setsize(qh, maxpoints)+numpoints);
         qh_errexit(qh, qh_ERRprec, NULL, NULL);
       }else {
         qh_fprintf(qh, qh->ferr, 6013, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh->hull_dim);
         qh_errexit(qh, qh_ERRinput, NULL, NULL);
       }
     }
   }
   for (k=sizinit; k < dim+1; k++) {
     maxpoint= NULL;
     maxdet= -REALmax;
     FOREACHpoint_(maxpoints) {
       if (!qh_setin(*simplex, point)) {
         det= qh_detsimplex(qh, point, *simplex, k, &nearzero);
         if ((det= fabs_(det)) > maxdet) {
           maxdet= det;
           maxpoint= point;
           maxnearzero= nearzero;
         }
       }
     }
     if (!maxpoint || maxnearzero) {
       zinc_(Zsearchpoints);
       if (!maxpoint) {
         trace0((qh, qh->ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
       }else {
         trace0((qh, qh->ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",
                 k+1, qh_pointid(qh, maxpoint), maxdet));
       }
       FORALLpoint_(qh, points, numpoints) {
         if (point == qh->GOODpointp)
           continue;
         if (!qh_setin(*simplex, point)) {
           det= qh_detsimplex(qh, point, *simplex, k, &nearzero);
           if ((det= fabs_(det)) > maxdet) {
             maxdet= det;
             maxpoint= point;
             maxnearzero= nearzero;
           }
         }
       }
     } /* !maxpoint */
     if (!maxpoint) {
       qh_fprintf(qh, qh->ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }
     qh_setappend(qh, simplex, maxpoint);
     trace1((qh, qh->ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
             qh_pointid(qh, maxpoint), k+1, maxdet));
   } /* k */
 } /* maxsimplex */
 
 /*---------------------------------
 
   qh_minabsval(qh, normal, dim )
     return minimum absolute value of a dim vector
 */
 realT qh_minabsval(qhT *qh, realT *normal, int dim) {
   realT minval= 0;
   realT maxval= 0;
   realT *colp;
   int k;
 
   for (k=dim, colp=normal; k--; colp++) {
     maximize_(maxval, *colp);
     minimize_(minval, *colp);
   }
   return fmax_(maxval, -minval);
 } /* minabsval */
 
 
 /*---------------------------------
 
   qh_mindif(qh, vecA, vecB, dim )
     return index of min abs. difference of two vectors
 */
 int qh_mindiff(qhT *qh, realT *vecA, realT *vecB, int dim) {
   realT mindiff= REALmax, diff;
   realT *vecAp= vecA, *vecBp= vecB;
   int k, mink= 0;
 
   for (k=0; k < dim; k++) {
     diff= *vecAp++ - *vecBp++;
     diff= fabs_(diff);
     if (diff < mindiff) {
       mindiff= diff;
       mink= k;
     }
   }
   return mink;
 } /* mindiff */
 
 
 
 /*---------------------------------
 
   qh_orientoutside(qh, facet  )
     make facet outside oriented via qh.interior_point
 
   returns:
     True if facet reversed orientation.
 */
 boolT qh_orientoutside(qhT *qh, facetT *facet) {
   int k;
   realT dist;
 
   qh_distplane(qh, qh->interior_point, facet, &dist);
   if (dist > 0) {
     for (k=qh->hull_dim; k--; )
       facet->normal[k]= -facet->normal[k];
     facet->offset= -facet->offset;
     return True;
   }
   return False;
 } /* orientoutside */
 
 /*---------------------------------
 
   qh_outerinner(qh, facet, outerplane, innerplane  )
     if facet and qh.maxoutdone (i.e., qh_check_maxout)
       returns outer and inner plane for facet
     else
       returns maximum outer and inner plane
     accounts for qh.JOGGLEmax
 
   see:
     qh_maxouter(qh), qh_check_bestdist(), qh_check_points()
 
   notes:
     outerplaner or innerplane may be NULL
     facet is const
     Does not error (QhullFacet)
 
     includes qh.DISTround for actual points
     adds another qh.DISTround if testing with floating point arithmetic
 */
 void qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {
   realT dist, mindist;
   vertexT *vertex, **vertexp;
 
   if (outerplane) {
     if (!qh_MAXoutside || !facet || !qh->maxoutdone) {
       *outerplane= qh_maxouter(qh);       /* includes qh.DISTround */
     }else { /* qh_MAXoutside ... */
 #if qh_MAXoutside
       *outerplane= facet->maxoutside + qh->DISTround;
 #endif
 
     }
     if (qh->JOGGLEmax < REALmax/2)
       *outerplane += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
   }
   if (innerplane) {
     if (facet) {
       mindist= REALmax;
       FOREACHvertex_(facet->vertices) {
         zinc_(Zdistio);
         qh_distplane(qh, vertex->point, facet, &dist);
         minimize_(mindist, dist);
       }
       *innerplane= mindist - qh->DISTround;
     }else
       *innerplane= qh->min_vertex - qh->DISTround;
     if (qh->JOGGLEmax < REALmax/2)
       *innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
   }
 } /* outerinner */
 
 /*---------------------------------
 
   qh_pointdist(qh, point1, point2, dim )
     return distance between two points
 
   notes:
     returns distance squared if 'dim' is negative
 */
 coordT qh_pointdist(qhT *qh, pointT *point1, pointT *point2, int dim) {
   coordT dist, diff;
   int k;
 
   dist= 0.0;
   for (k= (dim > 0 ? dim : -dim); k--; ) {
     diff= *point1++ - *point2++;
     dist += diff * diff;
   }
   if (dim > 0)
     return(sqrt(dist));
   return dist;
 } /* pointdist */
 
 
 /*---------------------------------
 
   qh_printmatrix(qh, fp, string, rows, numrow, numcol )
     print matrix to fp given by row vectors
     print string as header
 
   notes:
     print a vector by qh_printmatrix(qh, fp, "", &vect, 1, len)
 */
 void qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol) {
   realT *rowp;
   realT r; /*bug fix*/
   int i,k;
 
   qh_fprintf(qh, fp, 9001, "%s\n", string);
   for (i=0; i < numrow; i++) {
     rowp= rows[i];
     for (k=0; k < numcol; k++) {
       r= *rowp++;
       qh_fprintf(qh, fp, 9002, "%6.3g ", r);
     }
     qh_fprintf(qh, fp, 9003, "\n");
   }
 } /* printmatrix */
 
 
 /*---------------------------------
 
   qh_printpoints(qh, fp, string, points )
     print pointids to fp for a set of points
     if string, prints string and 'p' point ids
 */
 void qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points) {
   pointT *point, **pointp;
 
   if (string) {
     qh_fprintf(qh, fp, 9004, "%s", string);
     FOREACHpoint_(points)
       qh_fprintf(qh, fp, 9005, " p%d", qh_pointid(qh, point));
     qh_fprintf(qh, fp, 9006, "\n");
   }else {
     FOREACHpoint_(points)
       qh_fprintf(qh, fp, 9007, " %d", qh_pointid(qh, point));
     qh_fprintf(qh, fp, 9008, "\n");
   }
 } /* printpoints */
 
 
 /*---------------------------------
 
   qh_projectinput(qh)
     project input points using qh.lower_bound/upper_bound and qh->DELAUNAY
     if qh.lower_bound[k]=qh.upper_bound[k]= 0,
       removes dimension k
     if halfspace intersection
       removes dimension k from qh.feasible_point
     input points in qh->first_point, num_points, input_dim
 
   returns:
     new point array in qh->first_point of qh->hull_dim coordinates
     sets qh->POINTSmalloc
     if qh->DELAUNAY
       projects points to paraboloid
       lowbound/highbound is also projected
     if qh->ATinfinity
       adds point "at-infinity"
     if qh->POINTSmalloc
       frees old point array
 
   notes:
     checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
 
 
   design:
     sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
     determines newdim and newnum for qh->hull_dim and qh->num_points
     projects points to newpoints
     projects qh.lower_bound to itself
     projects qh.upper_bound to itself
     if qh->DELAUNAY
       if qh->ATINFINITY
         projects points to paraboloid
         computes "infinity" point as vertex average and 10% above all points
       else
         uses qh_setdelaunay to project points to paraboloid
 */
 void qh_projectinput(qhT *qh) {
   int k,i;
   int newdim= qh->input_dim, newnum= qh->num_points;
   signed char *project;
   int size= (qh->input_dim+1)*sizeof(*project);
   pointT *newpoints, *coord, *infinity;
   realT paraboloid, maxboloid= 0;
 
   project= (signed char*)qh_memalloc(qh, size);
   memset((char*)project, 0, (size_t)size);
   for (k=0; k < qh->input_dim; k++) {   /* skip Delaunay bound */
     if (qh->lower_bound[k] == 0 && qh->upper_bound[k] == 0) {
       project[k]= -1;
       newdim--;
     }
   }
   if (qh->DELAUNAY) {
     project[k]= 1;
     newdim++;
     if (qh->ATinfinity)
       newnum++;
   }
   if (newdim != qh->hull_dim) {
     qh_fprintf(qh, qh->ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh->hull_dim);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   if (!(newpoints=(coordT*)qh_malloc(newnum*newdim*sizeof(coordT)))){
     qh_fprintf(qh, qh->ferr, 6016, "qhull error: insufficient memory to project %d points\n",
            qh->num_points);
     qh_errexit(qh, qh_ERRmem, NULL, NULL);
   }
   qh_projectpoints(qh, project, qh->input_dim+1, qh->first_point,
                     qh->num_points, qh->input_dim, newpoints, newdim);
   trace1((qh, qh->ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));
   qh_projectpoints(qh, project, qh->input_dim+1, qh->lower_bound,
                     1, qh->input_dim+1, qh->lower_bound, newdim+1);
   qh_projectpoints(qh, project, qh->input_dim+1, qh->upper_bound,
                     1, qh->input_dim+1, qh->upper_bound, newdim+1);
   if (qh->HALFspace) {
     if (!qh->feasible_point) {
       qh_fprintf(qh, qh->ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }
     qh_projectpoints(qh, project, qh->input_dim, qh->feasible_point,
                       1, qh->input_dim, qh->feasible_point, newdim);
   }
   qh_memfree(qh, project, (qh->input_dim+1)*sizeof(*project));
   if (qh->POINTSmalloc)
     qh_free(qh->first_point);
   qh->first_point= newpoints;
   qh->POINTSmalloc= True;
   if (qh->DELAUNAY && qh->ATinfinity) {
     coord= qh->first_point;
     infinity= qh->first_point + qh->hull_dim * qh->num_points;
     for (k=qh->hull_dim-1; k--; )
       infinity[k]= 0.0;
     for (i=qh->num_points; i--; ) {
       paraboloid= 0.0;
       for (k=0; k < qh->hull_dim-1; k++) {
         paraboloid += *coord * *coord;
         infinity[k] += *coord;
         coord++;
       }
       *(coord++)= paraboloid;
       maximize_(maxboloid, paraboloid);
     }
     /* coord == infinity */
     for (k=qh->hull_dim-1; k--; )
       *(coord++) /= qh->num_points;
     *(coord++)= maxboloid * 1.1;
     qh->num_points++;
     trace0((qh, qh->ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
   }else if (qh->DELAUNAY)  /* !qh->ATinfinity */
     qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);
 } /* projectinput */
 
 
 /*---------------------------------
 
   qh_projectpoints(qh, project, n, points, numpoints, dim, newpoints, newdim )
     project points/numpoints/dim to newpoints/newdim
     if project[k] == -1
       delete dimension k
     if project[k] == 1
       add dimension k by duplicating previous column
     n is size of project
 
   notes:
     newpoints may be points if only adding dimension at end
 
   design:
     check that 'project' and 'newdim' agree
     for each dimension
       if project == -1
         skip dimension
       else
         determine start of column in newpoints
         determine start of column in points
           if project == +1, duplicate previous column
         copy dimension (column) from points to newpoints
 */
 void qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,
         int numpoints, int dim, realT *newpoints, int newdim) {
   int testdim= dim, oldk=0, newk=0, i,j=0,k;
   realT *newp, *oldp;
 
   for (k=0; k < n; k++)
     testdim += project[k];
   if (testdim != newdim) {
     qh_fprintf(qh, qh->ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
       newdim, testdim);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   for (j=0; j= dim)
           continue;
         oldp= points+oldk;
       }else
         oldp= points+oldk++;
       for (i=numpoints; i--; ) {
         *newp= *oldp;
         newp += newdim;
         oldp += dim;
       }
     }
     if (oldk >= dim)
       break;
   }
   trace1((qh, qh->ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
     numpoints, dim, newdim));
 } /* projectpoints */
 
 
 /*---------------------------------
 
   qh_rotateinput(qh, rows )
     rotate input using row matrix
     input points given by qh->first_point, num_points, hull_dim
     assumes rows[dim] is a scratch buffer
     if qh->POINTSmalloc, overwrites input points, else mallocs a new array
 
   returns:
     rotated input
     sets qh->POINTSmalloc
 
   design:
     see qh_rotatepoints
 */
 void qh_rotateinput(qhT *qh, realT **rows) {
 
   if (!qh->POINTSmalloc) {
     qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);
     qh->POINTSmalloc= True;
   }
   qh_rotatepoints(qh, qh->first_point, qh->num_points, qh->hull_dim, rows);
 }  /* rotateinput */
 
 /*---------------------------------
 
   qh_rotatepoints(qh, points, numpoints, dim, row )
     rotate numpoints points by a d-dim row matrix
     assumes rows[dim] is a scratch buffer
 
   returns:
     rotated points in place
 
   design:
     for each point
       for each coordinate
         use row[dim] to compute partial inner product
       for each coordinate
         rotate by partial inner product
 */
 void qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **row) {
   realT *point, *rowi, *coord= NULL, sum, *newval;
   int i,j,k;
 
   if (qh->IStracing >= 1)
     qh_printmatrix(qh, qh->ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
   for (point= points, j= numpoints; j--; point += dim) {
     newval= row[dim];
     for (i=0; i < dim; i++) {
       rowi= row[i];
       coord= point;
       for (sum= 0.0, k= dim; k--; )
         sum += *rowi++ * *coord++;
       *(newval++)= sum;
     }
     for (k=dim; k--; )
       *(--coord)= *(--newval);
   }
 } /* rotatepoints */
 
 
 /*---------------------------------
 
   qh_scaleinput(qh)
     scale input points using qh->low_bound/high_bound
     input points given by qh->first_point, num_points, hull_dim
     if qh->POINTSmalloc, overwrites input points, else mallocs a new array
 
   returns:
     scales coordinates of points to low_bound[k], high_bound[k]
     sets qh->POINTSmalloc
 
   design:
     see qh_scalepoints
 */
 void qh_scaleinput(qhT *qh) {
 
   if (!qh->POINTSmalloc) {
     qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);
     qh->POINTSmalloc= True;
   }
   qh_scalepoints(qh, qh->first_point, qh->num_points, qh->hull_dim,
        qh->lower_bound, qh->upper_bound);
 }  /* scaleinput */
 
 /*---------------------------------
 
   qh_scalelast(qh, points, numpoints, dim, low, high, newhigh )
     scale last coordinate to [0,m] for Delaunay triangulations
     input points given by points, numpoints, dim
 
   returns:
     changes scale of last coordinate from [low, high] to [0, newhigh]
     overwrites last coordinate of each point
     saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
 
   notes:
     when called by qh_setdelaunay, low/high may not match actual data
 
   design:
     compute scale and shift factors
     apply to last coordinate of each point
 */
 void qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,
                    coordT high, coordT newhigh) {
   realT scale, shift;
   coordT *coord;
   int i;
   boolT nearzero= False;
 
   trace4((qh, qh->ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",
     low, high, newhigh));
   qh->last_low= low;
   qh->last_high= high;
   qh->last_newhigh= newhigh;
   scale= qh_divzero(qh, newhigh, high - low,
                   qh->MINdenom_1, &nearzero);
   if (nearzero) {
     if (qh->DELAUNAY)
       qh_fprintf(qh, qh->ferr, 6019, "qhull input error: can not scale last coordinate.  Input is cocircular\n   or cospherical.   Use option 'Qz' to add a point at infinity.\n");
     else
       qh_fprintf(qh, qh->ferr, 6020, "qhull input error: can not scale last coordinate.  New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",
                 newhigh, low, high, high-low);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   shift= - low * newhigh / (high-low);
   coord= points + dim - 1;
   for (i=numpoints; i--; coord += dim)
     *coord= *coord * scale + shift;
 } /* scalelast */
 
 /*---------------------------------
 
   qh_scalepoints(qh, points, numpoints, dim, newlows, newhighs )
     scale points to new lowbound and highbound
     retains old bound when newlow= -REALmax or newhigh= +REALmax
 
   returns:
     scaled points
     overwrites old points
 
   design:
     for each coordinate
       compute current low and high bound
       compute scale and shift factors
       scale all points
       enforce new low and high bound for all points
 */
 void qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,
         realT *newlows, realT *newhighs) {
   int i,k;
   realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
   boolT nearzero= False;
 
   for (k=0; k < dim; k++) {
     newhigh= newhighs[k];
     newlow= newlows[k];
     if (newhigh > REALmax/2 && newlow < -REALmax/2)
       continue;
     low= REALmax;
     high= -REALmax;
     for (i=numpoints, coord=points+k; i--; coord += dim) {
       minimize_(low, *coord);
       maximize_(high, *coord);
     }
     if (newhigh > REALmax/2)
       newhigh= high;
     if (newlow < -REALmax/2)
       newlow= low;
     if (qh->DELAUNAY && k == dim-1 && newhigh < newlow) {
       qh_fprintf(qh, qh->ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
                k, k, newhigh, newlow);
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     scale= qh_divzero(qh, newhigh - newlow, high - low,
                   qh->MINdenom_1, &nearzero);
     if (nearzero) {
       qh_fprintf(qh, qh->ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
               k, newlow, newhigh, low, high);
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     shift= (newlow * high - low * newhigh)/(high-low);
     coord= points+k;
     for (i=numpoints; i--; coord += dim)
       *coord= *coord * scale + shift;
     coord= points+k;
     if (newlow < newhigh) {
       mincoord= newlow;
       maxcoord= newhigh;
     }else {
       mincoord= newhigh;
       maxcoord= newlow;
     }
     for (i=numpoints; i--; coord += dim) {
       minimize_(*coord, maxcoord);  /* because of roundoff error */
       maximize_(*coord, mincoord);
     }
     trace0((qh, qh->ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
       k, low, high, newlow, newhigh, numpoints, scale, shift));
   }
 } /* scalepoints */
 
 
 /*---------------------------------
 
   qh_setdelaunay(qh, dim, count, points )
     project count points to dim-d paraboloid for Delaunay triangulation
 
     dim is one more than the dimension of the input set
     assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
 
     points is a dim*count realT array.  The first dim-1 coordinates
     are the coordinates of the first input point.  array[dim] is
     the first coordinate of the second input point.  array[2*dim] is
     the first coordinate of the third input point.
 
     if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
       calls qh_scalelast to scale the last coordinate the same as the other points
 
   returns:
     for each point
       sets point[dim-1] to sum of squares of coordinates
     scale points to 'Qbb' if needed
 
   notes:
     to project one point, use
       qh_setdelaunay(qh, qh->hull_dim, 1, point)
 
     Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
     the coordinates after the original projection.
 
 */
 void qh_setdelaunay(qhT *qh, int dim, int count, pointT *points) {
   int i, k;
   coordT *coordp, coord;
   realT paraboloid;
 
   trace0((qh, qh->ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
   coordp= points;
   for (i=0; i < count; i++) {
     coord= *coordp++;
     paraboloid= coord*coord;
     for (k=dim-2; k--; ) {
       coord= *coordp++;
       paraboloid += coord*coord;
     }
     *coordp++ = paraboloid;
   }
   if (qh->last_low < REALmax/2)
     qh_scalelast(qh, points, count, dim, qh->last_low, qh->last_high, qh->last_newhigh);
 } /* setdelaunay */
 
 
 /*---------------------------------
 
   qh_sethalfspace(qh, dim, coords, nextp, normal, offset, feasible )
     set point to dual of halfspace relative to feasible point
     halfspace is normal coefficients and offset.
 
   returns:
     false if feasible point is outside of hull (error message already reported)
     overwrites coordinates for point at dim coords
     nextp= next point (coords)
 
   design:
     compute distance from feasible point to halfspace
     divide each normal coefficient by -dist
 */
 boolT qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,
          coordT *normal, coordT *offset, coordT *feasible) {
   coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
   realT dist;
   realT r; /*bug fix*/
   int k;
   boolT zerodiv;
 
   dist= *offset;
   for (k=dim; k--; )
     dist += *(normp++) * *(feasiblep++);
   if (dist > 0)
     goto LABELerroroutside;
   normp= normal;
   if (dist < -qh->MINdenom) {
     for (k=dim; k--; )
       *(coordp++)= *(normp++) / -dist;
   }else {
     for (k=dim; k--; ) {
       *(coordp++)= qh_divzero(qh, *(normp++), -dist, qh->MINdenom_1, &zerodiv);
       if (zerodiv)
         goto LABELerroroutside;
     }
   }
   *nextp= coordp;
   if (qh->IStracing >= 4) {
     qh_fprintf(qh, qh->ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
     for (k=dim, coordp=coords; k--; ) {
       r= *coordp++;
       qh_fprintf(qh, qh->ferr, 8022, " %6.2g", r);
     }
     qh_fprintf(qh, qh->ferr, 8023, "\n");
   }
   return True;
 LABELerroroutside:
   feasiblep= feasible;
   normp= normal;
   qh_fprintf(qh, qh->ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
   for (k=dim; k--; )
     qh_fprintf(qh, qh->ferr, 8024, qh_REAL_1, r=*(feasiblep++));
   qh_fprintf(qh, qh->ferr, 8025, "\n     halfspace: ");
   for (k=dim; k--; )
     qh_fprintf(qh, qh->ferr, 8026, qh_REAL_1, r=*(normp++));
   qh_fprintf(qh, qh->ferr, 8027, "\n     at offset: ");
   qh_fprintf(qh, qh->ferr, 8028, qh_REAL_1, *offset);
   qh_fprintf(qh, qh->ferr, 8029, " and distance: ");
   qh_fprintf(qh, qh->ferr, 8030, qh_REAL_1, dist);
   qh_fprintf(qh, qh->ferr, 8031, "\n");
   return False;
 } /* sethalfspace */
 
 /*---------------------------------
 
   qh_sethalfspace_all(qh, dim, count, halfspaces, feasible )
     generate dual for halfspace intersection with feasible point
     array of count halfspaces
       each halfspace is normal coefficients followed by offset
       the origin is inside the halfspace if the offset is negative
 
   returns:
     malloc'd array of count X dim-1 points
 
   notes:
     call before qh_init_B or qh_initqhull_globals
     unused/untested code: please email bradb@shore.net if this works ok for you
     If using option 'Fp', also set qh->feasible_point. It is a malloc'd array
       that is freed by qh_freebuffers.
 
   design:
     see qh_sethalfspace
 */
 coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible) {
   int i, newdim;
   pointT *newpoints;
   coordT *coordp, *normalp, *offsetp;
 
   trace0((qh, qh->ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
   newdim= dim - 1;
   if (!(newpoints=(coordT*)qh_malloc(count*newdim*sizeof(coordT)))){
     qh_fprintf(qh, qh->ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
           count);
     qh_errexit(qh, qh_ERRmem, NULL, NULL);
   }
   coordp= newpoints;
   normalp= halfspaces;
   for (i=0; i < count; i++) {
     offsetp= normalp + newdim;
     if (!qh_sethalfspace(qh, newdim, coordp, &coordp, normalp, offsetp, feasible)) {
       qh_fprintf(qh, qh->ferr, 8032, "The halfspace was at index %d\n", i);
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     normalp= offsetp + 1;
   }
   return newpoints;
 } /* sethalfspace_all */
 
 
 /*---------------------------------
 
   qh_sharpnewfacets(qh)
 
   returns:
     true if could be an acute angle (facets in different quadrants)
 
   notes:
     for qh_findbest
 
   design:
     for all facets on qh.newfacet_list
       if two facets are in different quadrants
         set issharp
 */
 boolT qh_sharpnewfacets(qhT *qh) {
   facetT *facet;
   boolT issharp = False;
   int *quadrant, k;
 
   quadrant= (int*)qh_memalloc(qh, qh->hull_dim * sizeof(int));
   FORALLfacet_(qh->newfacet_list) {
     if (facet == qh->newfacet_list) {
       for (k=qh->hull_dim; k--; )
         quadrant[ k]= (facet->normal[ k] > 0);
     }else {
       for (k=qh->hull_dim; k--; ) {
         if (quadrant[ k] != (facet->normal[ k] > 0)) {
           issharp= True;
           break;
         }
       }
     }
     if (issharp)
       break;
   }
   qh_memfree(qh, quadrant, qh->hull_dim * sizeof(int));
   trace3((qh, qh->ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));
   return issharp;
 } /* sharpnewfacets */
 
 /*---------------------------------
 
   qh_voronoi_center(qh, dim, points )
     return Voronoi center for a set of points
     dim is the orginal dimension of the points
     gh.gm_matrix/qh.gm_row are scratch buffers
 
   returns:
     center as a temporary point
     if non-simplicial,
       returns center for max simplex of points
 
   notes:
     from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
 
   design:
     if non-simplicial
       determine max simplex for points
     translate point0 of simplex to origin
     compute sum of squares of diagonal
     compute determinate
     compute Voronoi center (see Bowyer & Woodwark)
 */
 pointT *qh_voronoi_center(qhT *qh, int dim, setT *points) {
   pointT *point, **pointp, *point0;
   pointT *center= (pointT*)qh_memalloc(qh, qh->center_size);
   setT *simplex;
   int i, j, k, size= qh_setsize(qh, points);
   coordT *gmcoord;
   realT *diffp, sum2, *sum2row, *sum2p, det, factor;
   boolT nearzero, infinite;
 
   if (size == dim+1)
     simplex= points;
   else if (size < dim+1) {
     qh_fprintf(qh, qh->ferr, 6025, "qhull internal error (qh_voronoi_center):\n  need at least %d points to construct a Voronoi center\n",
              dim+1);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     simplex= points;  /* never executed -- avoids warning */
   }else {
     simplex= qh_settemp(qh, dim+1);
     qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);
   }
   point0= SETfirstt_(simplex, pointT);
   gmcoord= qh->gm_matrix;
   for (k=0; k < dim; k++) {
     qh->gm_row[k]= gmcoord;
     FOREACHpoint_(simplex) {
       if (point != point0)
         *(gmcoord++)= point[k] - point0[k];
     }
   }
   sum2row= gmcoord;
   for (i=0; i < dim; i++) {
     sum2= 0.0;
     for (k=0; k < dim; k++) {
       diffp= qh->gm_row[k] + i;
       sum2 += *diffp * *diffp;
     }
     *(gmcoord++)= sum2;
   }
   det= qh_determinant(qh, qh->gm_row, dim, &nearzero);
   factor= qh_divzero(qh, 0.5, det, qh->MINdenom, &infinite);
   if (infinite) {
     for (k=dim; k--; )
       center[k]= qh_INFINITE;
     if (qh->IStracing)
       qh_printpoints(qh, qh->ferr, "qh_voronoi_center: at infinity for ", simplex);
   }else {
     for (i=0; i < dim; i++) {
       gmcoord= qh->gm_matrix;
       sum2p= sum2row;
       for (k=0; k < dim; k++) {
         qh->gm_row[k]= gmcoord;
         if (k == i) {
           for (j=dim; j--; )
             *(gmcoord++)= *sum2p++;
         }else {
           FOREACHpoint_(simplex) {
             if (point != point0)
               *(gmcoord++)= point[k] - point0[k];
           }
         }
       }
       center[i]= qh_determinant(qh, qh->gm_row, dim, &nearzero)*factor + point0[i];
     }
 #ifndef qh_NOtrace
     if (qh->IStracing >= 3) {
       qh_fprintf(qh, qh->ferr, 8033, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
       qh_printmatrix(qh, qh->ferr, "center:", ¢er, 1, dim);
       if (qh->IStracing >= 5) {
         qh_printpoints(qh, qh->ferr, "points", simplex);
         FOREACHpoint_(simplex)
           qh_fprintf(qh, qh->ferr, 8034, "p%d dist %.2g, ", qh_pointid(qh, point),
                    qh_pointdist(qh, point, center, dim));
         qh_fprintf(qh, qh->ferr, 8035, "\n");
       }
     }
 #endif
   }
   if (simplex != points)
     qh_settempfree(qh, &simplex);
   return center;
 } /* voronoi_center */
 
diff --git a/src/libqhullr/geom_r.c b/src/libqhullr/geom_r.c
index 085662c..6c8a93b 100644
--- a/src/libqhullr/geom_r.c
+++ b/src/libqhullr/geom_r.c
@@ -1,1234 +1,1234 @@
 /*
  ---------------------------------
 
    geom_r.c
    geometric routines of qhull
 
    see qh-geom.htm and geom_r.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/geom_r.c#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/geom_r.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    infrequent code goes into geom2_r.c
 */
 
 #include "qhull_ra.h"
 
 /*---------------------------------
 
   qh_distplane(qh, point, facet, dist )
     return distance from point to facet
 
   returns:
     dist
     if qh.RANDOMdist, joggles result
 
   notes:
     dist > 0 if point is above facet (i.e., outside)
     does not error (for qh_sortfacets, qh_outerinner)
 
   see:
     qh_distnorm in geom2_r.c
     qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies
 */
 void qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist) {
   coordT *normal= facet->normal, *coordp, randr;
   int k;
 
   switch (qh->hull_dim){
   case 2:
     *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
     break;
   case 3:
     *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
     break;
   case 4:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
     break;
   case 5:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
     break;
   case 6:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
     break;
   case 7:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
     break;
   case 8:
     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
     break;
   default:
     *dist= facet->offset;
     coordp= point;
     for (k=qh->hull_dim; k--; )
       *dist += *coordp++ * *normal++;
     break;
   }
   zinc_(Zdistplane);
   if (!qh->RANDOMdist && qh->IStracing < 4)
     return;
   if (qh->RANDOMdist) {
     randr= qh_RANDOMint;
     *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
       qh->RANDOMfactor * qh->MAXabs_coord;
   }
   if (qh->IStracing >= 4) {
     qh_fprintf(qh, qh->ferr, 8001, "qh_distplane: ");
     qh_fprintf(qh, qh->ferr, 8002, qh_REAL_1, *dist);
     qh_fprintf(qh, qh->ferr, 8003, "from p%d to f%d\n", qh_pointid(qh, point), facet->id);
   }
   return;
 } /* distplane */
 
 
 /*---------------------------------
 
   qh_findbest(qh, point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
     find facet that is furthest below a point
     for upperDelaunay facets
       returns facet only if !qh_NOupper and clearly above
 
   input:
     starts search at 'startfacet' (can not be flipped)
     if !bestoutside(qh_ALL), stops at qh.MINoutside
 
   returns:
     best facet (reports error if NULL)
     early out if isoutside defined and bestdist > qh.MINoutside
     dist is distance to facet
     isoutside is true if point is outside of facet
     numpart counts the number of distance tests
 
   see also:
     qh_findbestnew()
 
   notes:
     If merging (testhorizon), searches horizon facets of coplanar best facets because
     after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
       avoid calls to distplane, function calls, and real number operations.
     caller traces result
     Optimized for outside points.   Tried recording a search set for qh_findhorizon.
     Made code more complicated.
 
   when called by qh_partitionvisible():
     indicated by qh_ISnewfacets
     qh.newfacet_list is list of simplicial, new facets
     qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
     qh.bestfacet_notsharp set if qh_sharpnewfacets returns False
 
   when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),
                  qh_check_bestdist(), qh_addpoint()
     indicated by !qh_ISnewfacets
     returns best facet in neighborhood of given facet
       this is best facet overall if dist > -   qh.MAXcoplanar
         or hull has at least a "spherical" curvature
 
   design:
     initialize and test for early exit
     repeat while there are better facets
       for each neighbor of facet
         exit if outside facet found
         test for better facet
     if point is inside and partitioning
       test for new facets with a "sharp" intersection
       if so, future calls go to qh_findbestnew()
     test horizon facets
 */
 facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
                      boolT bestoutside, boolT isnewfacets, boolT noupper,
                      realT *dist, boolT *isoutside, int *numpart) {
   realT bestdist= -REALmax/2 /* avoid underflow */;
   facetT *facet, *neighbor, **neighborp;
   facetT *bestfacet= NULL, *lastfacet= NULL;
   int oldtrace= qh->IStracing;
   unsigned int visitid= ++qh->visit_id;
   int numpartnew=0;
   boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
 
   zinc_(Zfindbest);
   if (qh->IStracing >= 3 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
     if (qh->TRACElevel > qh->IStracing)
       qh->IStracing= qh->TRACElevel;
     qh_fprintf(qh, qh->ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n",
              qh_pointid(qh, point), startfacet->id, isnewfacets, bestoutside, qh->MINoutside);
     qh_fprintf(qh, qh->ferr, 8005, "  testhorizon? %d noupper? %d", testhorizon, noupper);
     qh_fprintf(qh, qh->ferr, 8006, "  Last point added was p%d.", qh->furthest_id);
     qh_fprintf(qh, qh->ferr, 8007, "  Last merge was #%d.  max_outside %2.2g\n", zzval_(Ztotmerge), qh->max_outside);
   }
   if (isoutside)
     *isoutside= True;
   if (!startfacet->flipped) {  /* test startfacet */
     *numpart= 1;
     qh_distplane(qh, point, startfacet, dist);  /* this code is duplicated below */
     if (!bestoutside && *dist >= qh->MINoutside
     && (!startfacet->upperdelaunay || !noupper)) {
       bestfacet= startfacet;
       goto LABELreturn_best;
     }
     bestdist= *dist;
     if (!startfacet->upperdelaunay) {
       bestfacet= startfacet;
     }
   }else
     *numpart= 0;
   startfacet->visitid= visitid;
   facet= startfacet;
   while (facet) {
     trace4((qh, qh->ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
                 facet->id, bestdist, getid_(bestfacet)));
     lastfacet= facet;
     FOREACHneighbor_(facet) {
       if (!neighbor->newfacet && isnewfacets)
         continue;
       if (neighbor->visitid == visitid)
         continue;
       neighbor->visitid= visitid;
       if (!neighbor->flipped) {  /* code duplicated above */
         (*numpart)++;
         qh_distplane(qh, point, neighbor, dist);
         if (*dist > bestdist) {
           if (!bestoutside && *dist >= qh->MINoutside
           && (!neighbor->upperdelaunay || !noupper)) {
             bestfacet= neighbor;
             goto LABELreturn_best;
           }
           if (!neighbor->upperdelaunay) {
             bestfacet= neighbor;
             bestdist= *dist;
             break; /* switch to neighbor */
           }else if (!bestfacet) {
             bestdist= *dist;
             break; /* switch to neighbor */
           }
         } /* end of *dist>bestdist */
       } /* end of !flipped */
     } /* end of FOREACHneighbor */
     facet= neighbor;  /* non-NULL only if *dist>bestdist */
   } /* end of while facet (directed search) */
   if (isnewfacets) {
     if (!bestfacet) {
       bestdist= -REALmax/2;
       bestfacet= qh_findbestnew(qh, point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew);
       testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
     }else if (!qh->findbest_notsharp && bestdist < - qh->DISTround) {
       if (qh_sharpnewfacets(qh)) {
         /* seldom used, qh_findbestnew will retest all facets */
         zinc_(Zfindnewsharp);
         bestfacet= qh_findbestnew(qh, point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
         testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
         qh->findbestnew= True;
       }else
         qh->findbest_notsharp= True;
     }
   }
   if (!bestfacet)
     bestfacet= qh_findbestlower(qh, lastfacet, point, &bestdist, numpart);
   if (testhorizon)
     bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
   *dist= bestdist;
   if (isoutside && bestdist < qh->MINoutside)
     *isoutside= False;
 LABELreturn_best:
   zadd_(Zfindbesttot, *numpart);
   zmax_(Zfindbestmax, *numpart);
   (*numpart) += numpartnew;
   qh->IStracing= oldtrace;
   return bestfacet;
 }  /* findbest */
 
 
 /*---------------------------------
 
   qh_findbesthorizon(qh, qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
     search coplanar and better horizon facets from startfacet/bestdist
     ischeckmax turns off statistics and minsearch update
     all arguments must be initialized
   returns(ischeckmax):
     best facet
   returns(!ischeckmax):
     best facet that is not upperdelaunay
     allows upperdelaunay that is clearly outside
   returns:
     bestdist is distance to bestfacet
     numpart -- updates number of distance tests
 
   notes:
     no early out -- use qh_findbest() or qh_findbestnew()
     Searches coplanar or better horizon facets
 
   when called by qh_check_maxout() (qh_IScheckmax)
     startfacet must be closest to the point
       Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
       even though other facets are below the point.
     updates facet->maxoutside for good, visited facets
     may return NULL
 
     searchdist is qh.max_outside + 2 * DISTround
       + max( MINvisible('Vn'), MAXcoplanar('Un'));
     This setting is a guess.  It must be at least max_outside + 2*DISTround
     because a facet may have a geometric neighbor across a vertex
 
   design:
     for each horizon facet of coplanar best facets
       continue if clearly inside
       unless upperdelaunay or clearly outside
          update best facet
 */
 facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
   facetT *bestfacet= startfacet;
   realT dist;
   facetT *neighbor, **neighborp, *facet;
   facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */
   int numpartinit= *numpart, coplanarfacetset_size;
   unsigned int visitid= ++qh->visit_id;
   boolT newbest= False; /* for tracing */
   realT minsearch, searchdist;  /* skip facets that are too far from point */
 
   if (!ischeckmax) {
     zinc_(Zfindhorizon);
   }else {
 #if qh_MAXoutside
     if ((!qh->ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
       startfacet->maxoutside= *bestdist;
 #endif
   }
   searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */
   minsearch= *bestdist - searchdist;
   if (ischeckmax) {
     /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
     minimize_(minsearch, -searchdist);
   }
   coplanarfacetset_size= 0;
   facet= startfacet;
   while (True) {
     trace4((qh, qh->ferr, 4002, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n",
                 facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
                 minsearch, searchdist));
     FOREACHneighbor_(facet) {
       if (neighbor->visitid == visitid)
         continue;
       neighbor->visitid= visitid;
       if (!neighbor->flipped) {
         qh_distplane(qh, point, neighbor, &dist);
         (*numpart)++;
         if (dist > *bestdist) {
           if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh->MINoutside)) {
             bestfacet= neighbor;
             *bestdist= dist;
             newbest= True;
             if (!ischeckmax) {
               minsearch= dist - searchdist;
               if (dist > *bestdist + searchdist) {
                 zinc_(Zfindjump);  /* everything in qh.coplanarfacetset at least searchdist below */
                 coplanarfacetset_size= 0;
               }
             }
           }
         }else if (dist < minsearch)
           continue;  /* if ischeckmax, dist can't be positive */
 #if qh_MAXoutside
         if (ischeckmax && dist > neighbor->maxoutside)
           neighbor->maxoutside= dist;
 #endif
       } /* end of !flipped */
       if (nextfacet) {
         if (!coplanarfacetset_size++) {
           SETfirst_(qh->coplanarfacetset)= nextfacet;
           SETtruncate_(qh->coplanarfacetset, 1);
         }else
           qh_setappend(qh, &qh->coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
                                                  and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
       }
       nextfacet= neighbor;
     } /* end of EACHneighbor */
     facet= nextfacet;
     if (facet)
       nextfacet= NULL;
     else if (!coplanarfacetset_size)
       break;
     else if (!--coplanarfacetset_size) {
       facet= SETfirstt_(qh->coplanarfacetset, facetT);
       SETtruncate_(qh->coplanarfacetset, 0);
     }else
       facet= (facetT*)qh_setdellast(qh->coplanarfacetset);
   } /* while True, for each facet in qh.coplanarfacetset */
   if (!ischeckmax) {
     zadd_(Zfindhorizontot, *numpart - numpartinit);
     zmax_(Zfindhorizonmax, *numpart - numpartinit);
     if (newbest)
       zinc_(Zparthorizon);
   }
   trace4((qh, qh->ferr, 4003, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));
   return bestfacet;
 }  /* findbesthorizon */
 
 /*---------------------------------
 
   qh_findbestnew(qh, point, startfacet, dist, isoutside, numpart )
     find best newfacet for point
     searches all of qh.newfacet_list starting at startfacet
     searches horizon facets of coplanar best newfacets
     searches all facets if startfacet == qh.facet_list
   returns:
     best new or horizon facet that is not upperdelaunay
     early out if isoutside and not 'Qf'
     dist is distance to facet
     isoutside is true if point is outside of facet
     numpart is number of distance tests
 
   notes:
     Always used for merged new facets (see qh_USEfindbestnew)
     Avoids upperdelaunay facet unless (isoutside and outside)
 
     Uses qh.visit_id, qh.coplanarfacetset.
     If share visit_id with qh_findbest, coplanarfacetset is incorrect.
 
     If merging (testhorizon), searches horizon facets of coplanar best facets because
     a point maybe coplanar to the bestfacet, below its horizon facet,
     and above a horizon facet of a coplanar newfacet.  For example,
       rbox 1000 s Z1 G1e-13 | qhull
       rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc
 
     qh_findbestnew() used if
        qh_sharpnewfacets -- newfacets contains a sharp angle
        if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)
 
   see also:
     qh_partitionall() and qh_findbest()
 
   design:
     for each new facet starting from startfacet
       test distance from point to facet
       return facet if clearly outside
       unless upperdelaunay and a lowerdelaunay exists
          update best facet
     test horizon facets
 */
 facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
            realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
   realT bestdist= -REALmax/2;
   facetT *bestfacet= NULL, *facet;
   int oldtrace= qh->IStracing, i;
   unsigned int visitid= ++qh->visit_id;
   realT distoutside= 0.0;
   boolT isdistoutside; /* True if distoutside is defined */
   boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
 
   if (!startfacet) {
     if (qh->MERGING)
       qh_fprintf(qh, qh->ferr, 6001, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
     else
       qh_fprintf(qh, qh->ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
               qh->furthest_id);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   zinc_(Zfindnew);
   if (qh->BESToutside || bestoutside)
     isdistoutside= False;
   else {
     isdistoutside= True;
     distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
   }
   if (isoutside)
     *isoutside= True;
   *numpart= 0;
   if (qh->IStracing >= 3 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
     if (qh->TRACElevel > qh->IStracing)
       qh->IStracing= qh->TRACElevel;
     qh_fprintf(qh, qh->ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",
              qh_pointid(qh, point), startfacet->id, isdistoutside, distoutside);
     qh_fprintf(qh, qh->ferr, 8009, "  Last point added p%d visitid %d.",  qh->furthest_id, visitid);
     qh_fprintf(qh, qh->ferr, 8010, "  Last merge was #%d.\n", zzval_(Ztotmerge));
   }
   /* visit all new facets starting with startfacet, maybe qh->facet_list */
   for (i=0, facet=startfacet; i < 2; i++, facet= qh->newfacet_list) {
     FORALLfacet_(facet) {
       if (facet == startfacet && i)
         break;
       facet->visitid= visitid;
       if (!facet->flipped) {
         qh_distplane(qh, point, facet, dist);
         (*numpart)++;
         if (*dist > bestdist) {
           if (!facet->upperdelaunay || *dist >= qh->MINoutside) {
             bestfacet= facet;
             if (isdistoutside && *dist >= distoutside)
               goto LABELreturn_bestnew;
             bestdist= *dist;
           }
         }
       } /* end of !flipped */
     } /* FORALLfacet from startfacet or qh->newfacet_list */
   }
   if (testhorizon || !bestfacet)
     bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,
                                         !qh_NOupper, &bestdist, numpart);
   *dist= bestdist;
   if (isoutside && *dist < qh->MINoutside)
     *isoutside= False;
 LABELreturn_bestnew:
   zadd_(Zfindnewtot, *numpart);
   zmax_(Zfindnewmax, *numpart);
   trace4((qh, qh->ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));
   qh->IStracing= oldtrace;
   return bestfacet;
 }  /* findbestnew */
 
 /* ============ hyperplane functions -- keep code together [?] ============ */
 
 /*---------------------------------
 
   qh_backnormal(qh, rows, numrow, numcol, sign, normal, nearzero )
     given an upper-triangular rows array and a sign,
     solve for normal equation x using back substitution over rows U
 
   returns:
      normal= x
 
      if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),
        if fails on last row
          this means that the hyperplane intersects [0,..,1]
          sets last coordinate of normal to sign
        otherwise
          sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
          sets nearzero
 
   notes:
      assumes numrow == numcol-1
 
      see Golub & van Loan 4.4-9 for back substitution
 
      solves Ux=b where Ax=b and PA=LU
      b= [0,...,0,sign or 0]  (sign is either -1 or +1)
      last row of A= [0,...,0,1]
 
      1) Ly=Pb == y=b since P only permutes the 0's of   b
 
   design:
     for each row from end
       perform back substitution
       if near zero
         use qh_divzero for division
         if zero divide and not last row
           set tail of normal to 0
 */
 void qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign,
         coordT *normal, boolT *nearzero) {
   int i, j;
   coordT *normalp, *normal_tail, *ai, *ak;
   realT diagonal;
   boolT waszero;
   int zerocol= -1;
 
   normalp= normal + numcol - 1;
   *normalp--= (sign ? -1.0 : 1.0);
   for (i=numrow; i--; ) {
     *normalp= 0.0;
     ai= rows[i] + i + 1;
     ak= normalp+1;
     for (j=i+1; j < numcol; j++)
       *normalp -= *ai++ * *ak++;
     diagonal= (rows[i])[i];
     if (fabs_(diagonal) > qh->MINdenom_2)
       *(normalp--) /= diagonal;
     else {
       waszero= False;
       *normalp= qh_divzero(qh, *normalp, diagonal, qh->MINdenom_1_2, &waszero);
       if (waszero) {
         zerocol= i;
         *(normalp--)= (sign ? -1.0 : 1.0);
         for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
           *normal_tail= 0.0;
       }else
         normalp--;
     }
   }
   if (zerocol != -1) {
     zzinc_(Zback0);
     *nearzero= True;
     trace4((qh, qh->ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));
     qh_precision(qh, "zero diagonal on back substitution");
   }
 } /* backnormal */
 
 /*---------------------------------
 
   qh_gausselim(qh, rows, numrow, numcol, sign )
     Gaussian elimination with partial pivoting
 
   returns:
     rows is upper triangular (includes row exchanges)
     flips sign for each row exchange
     sets nearzero if pivot[k] < qh.NEARzero[k], else clears it
 
   notes:
     if nearzero, the determinant's sign may be incorrect.
     assumes numrow <= numcol
 
   design:
     for each row
       determine pivot and exchange rows if necessary
       test for near zero
       perform gaussian elimination step
 */
 void qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
   realT *ai, *ak, *rowp, *pivotrow;
   realT n, pivot, pivot_abs= 0.0, temp;
   int i, j, k, pivoti, flip=0;
 
   *nearzero= False;
   for (k=0; k < numrow; k++) {
     pivot_abs= fabs_((rows[k])[k]);
     pivoti= k;
     for (i=k+1; i < numrow; i++) {
       if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
         pivot_abs= temp;
         pivoti= i;
       }
     }
     if (pivoti != k) {
       rowp= rows[pivoti];
       rows[pivoti]= rows[k];
       rows[k]= rowp;
       *sign ^= 1;
       flip ^= 1;
     }
     if (pivot_abs <= qh->NEARzero[k]) {
       *nearzero= True;
       if (pivot_abs == 0.0) {   /* remainder of column == 0 */
         if (qh->IStracing >= 4) {
           qh_fprintf(qh, qh->ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh->DISTround);
           qh_printmatrix(qh, qh->ferr, "Matrix:", rows, numrow, numcol);
         }
         zzinc_(Zgauss0);
         qh_precision(qh, "zero pivot for Gaussian elimination");
         goto LABELnextcol;
       }
     }
     pivotrow= rows[k] + k;
     pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
     for (i=k+1; i < numrow; i++) {
       ai= rows[i] + k;
       ak= pivotrow;
       n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
       for (j= numcol - (k+1); j--; )
         *ai++ -= n * *ak++;
     }
   LABELnextcol:
     ;
   }
   wmin_(Wmindenom, pivot_abs);  /* last pivot element */
   if (qh->IStracing >= 5)
     qh_printmatrix(qh, qh->ferr, "qh_gausselem: result", rows, numrow, numcol);
 } /* gausselim */
 
 
 /*---------------------------------
 
   qh_getangle(qh, vect1, vect2 )
     returns the dot product of two vectors
     if qh.RANDOMdist, joggles result
 
   notes:
     the angle may be > 1.0 or < -1.0 because of roundoff errors
 
 */
 realT qh_getangle(qhT *qh, pointT *vect1, pointT *vect2) {
   realT angle= 0, randr;
   int k;
 
   for (k=qh->hull_dim; k--; )
     angle += *vect1++ * *vect2++;
   if (qh->RANDOMdist) {
     randr= qh_RANDOMint;
     angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
       qh->RANDOMfactor;
   }
   trace4((qh, qh->ferr, 4006, "qh_getangle: %2.2g\n", angle));
   return(angle);
 } /* getangle */
 
 
 /*---------------------------------
 
   qh_getcenter(qh, vertices )
     returns arithmetic center of a set of vertices as a new point
 
   notes:
     allocates point array for center
 */
 pointT *qh_getcenter(qhT *qh, setT *vertices) {
   int k;
   pointT *center, *coord;
   vertexT *vertex, **vertexp;
   int count= qh_setsize(qh, vertices);
 
   if (count < 2) {
     qh_fprintf(qh, qh->ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   center= (pointT *)qh_memalloc(qh, qh->normal_size);
   for (k=0; k < qh->hull_dim; k++) {
     coord= center+k;
     *coord= 0.0;
     FOREACHvertex_(vertices)
       *coord += vertex->point[k];
     *coord /= count;
   }
   return(center);
 } /* getcenter */
 
 
 /*---------------------------------
 
   qh_getcentrum(qh, facet )
     returns the centrum for a facet as a new point
 
   notes:
     allocates the centrum
 */
 pointT *qh_getcentrum(qhT *qh, facetT *facet) {
   realT dist;
   pointT *centrum, *point;
 
   point= qh_getcenter(qh, facet->vertices);
   zzinc_(Zcentrumtests);
   qh_distplane(qh, point, facet, &dist);
   centrum= qh_projectpoint(qh, point, facet, dist);
   qh_memfree(qh, point, qh->normal_size);
   trace4((qh, qh->ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
           facet->id, qh_setsize(qh, facet->vertices), dist));
   return centrum;
 } /* getcentrum */
 
 
 /*---------------------------------
 
   qh_getdistance(qh, facet, neighbor, mindist, maxdist )
     returns the maxdist and mindist distance of any vertex from neighbor
 
   returns:
     the max absolute value
 
   design:
     for each vertex of facet that is not in neighbor
       test the distance from vertex to neighbor
 */
 realT qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {
   vertexT *vertex, **vertexp;
   realT dist, maxd, mind;
 
   FOREACHvertex_(facet->vertices)
     vertex->seen= False;
   FOREACHvertex_(neighbor->vertices)
     vertex->seen= True;
   mind= 0.0;
   maxd= 0.0;
   FOREACHvertex_(facet->vertices) {
     if (!vertex->seen) {
       zzinc_(Zbestdist);
       qh_distplane(qh, vertex->point, neighbor, &dist);
       if (dist < mind)
         mind= dist;
       else if (dist > maxd)
         maxd= dist;
     }
   }
   *mindist= mind;
   *maxdist= maxd;
   mind= -mind;
   if (maxd > mind)
     return maxd;
   else
     return mind;
 } /* getdistance */
 
 
 /*---------------------------------
 
   qh_normalize(qh, normal, dim, toporient )
     normalize a vector and report if too small
     does not use min norm
 
   see:
     qh_normalize2
 */
 void qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient) {
   qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
 } /* normalize */
 
 /*---------------------------------
 
   qh_normalize2(qh, normal, dim, toporient, minnorm, ismin )
     normalize a vector and report if too small
     qh.MINdenom/MINdenom1 are the upper limits for divide overflow
 
   returns:
     normalized vector
     flips sign if !toporient
     if minnorm non-NULL,
       sets ismin if normal < minnorm
 
   notes:
     if zero norm
        sets all elements to sqrt(1.0/dim)
     if divide by zero (divzero())
        sets largest element to   +/-1
        bumps Znearlysingular
 
   design:
     computes norm
     test for minnorm
     if not near zero
       normalizes normal
     else if zero norm
       sets normal to standard value
     else
       uses qh_divzero to normalize
       if nearzero
         sets norm to direction of maximum value
 */
 void qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
             realT *minnorm, boolT *ismin) {
   int k;
   realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
   boolT zerodiv;
 
   norm1= normal+1;
   norm2= normal+2;
   norm3= normal+3;
   if (dim == 2)
     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
   else if (dim == 3)
     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
   else if (dim == 4) {
     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
                + (*norm3)*(*norm3));
   }else if (dim > 4) {
     norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
                + (*norm3)*(*norm3);
     for (k=dim-4, colp=normal+4; k--; colp++)
       norm += (*colp) * (*colp);
     norm= sqrt(norm);
   }
   if (minnorm) {
     if (norm < *minnorm)
       *ismin= True;
     else
       *ismin= False;
   }
   wmin_(Wmindenom, norm);
   if (norm > qh->MINdenom) {
     if (!toporient)
       norm= -norm;
     *normal /= norm;
     *norm1 /= norm;
     if (dim == 2)
       ; /* all done */
     else if (dim == 3)
       *norm2 /= norm;
     else if (dim == 4) {
       *norm2 /= norm;
       *norm3 /= norm;
     }else if (dim >4) {
       *norm2 /= norm;
       *norm3 /= norm;
       for (k=dim-4, colp=normal+4; k--; )
         *colp++ /= norm;
     }
   }else if (norm == 0.0) {
     temp= sqrt(1.0/dim);
     for (k=dim, colp=normal; k--; )
       *colp++ = temp;
   }else {
     if (!toporient)
       norm= -norm;
     for (k=dim, colp=normal; k--; colp++) { /* k used below */
       temp= qh_divzero(qh, *colp, norm, qh->MINdenom_1, &zerodiv);
       if (!zerodiv)
         *colp= temp;
       else {
         maxp= qh_maxabsval(qh, normal, dim);
         temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
         for (k=dim, colp=normal; k--; colp++)
           *colp= 0.0;
         *maxp= temp;
         zzinc_(Znearlysingular);
         trace0((qh, qh->ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",
                norm, qh->furthest_id));
         return;
       }
     }
   }
 } /* normalize */
 
 
 /*---------------------------------
 
   qh_projectpoint(qh, point, facet, dist )
     project point onto a facet by dist
 
   returns:
     returns a new point
 
   notes:
     if dist= distplane(point,facet)
       this projects point to hyperplane
     assumes qh_memfree_() is valid for normal_size
 */
 pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist) {
   pointT *newpoint, *np, *normal;
   int normsize= qh->normal_size;
   int k;
   void **freelistp; /* used !qh_NOmem */
 
   qh_memalloc_(qh, normsize, freelistp, newpoint, pointT);
   np= newpoint;
   normal= facet->normal;
   for (k=qh->hull_dim; k--; )
     *(np++)= *point++ - dist * *normal++;
   return(newpoint);
 } /* projectpoint */
 
 
 /*---------------------------------
 
   qh_setfacetplane(qh, facet )
     sets the hyperplane for a facet
     if qh.RANDOMdist, joggles hyperplane
 
   notes:
     uses global buffers qh.gm_matrix and qh.gm_row
     overwrites facet->normal if already defined
     updates Wnewvertex if PRINTstatistics
     sets facet->upperdelaunay if upper envelope of Delaunay triangulation
 
   design:
     copy vertex coordinates to qh.gm_matrix/gm_row
     compute determinate
     if nearzero
       recompute determinate with gaussian elimination
       if nearzero
         force outside orientation by testing interior point
 */
 void qh_setfacetplane(qhT *qh, facetT *facet) {
   pointT *point;
   vertexT *vertex, **vertexp;
   int normsize= qh->normal_size;
   int k,i, oldtrace= 0;
   realT dist;
   void **freelistp; /* used !qh_NOmem */
   coordT *coord, *gmcoord;
   pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
   boolT nearzero= False;
 
   zzinc_(Zsetplane);
   if (!facet->normal)
     qh_memalloc_(qh, normsize, freelistp, facet->normal, coordT);
   if (facet == qh->tracefacet) {
     oldtrace= qh->IStracing;
     qh->IStracing= 5;
     qh_fprintf(qh, qh->ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);
     qh_fprintf(qh, qh->ferr, 8013, "  Last point added to hull was p%d.", qh->furthest_id);
     if (zzval_(Ztotmerge))
       qh_fprintf(qh, qh->ferr, 8014, "  Last merge was #%d.", zzval_(Ztotmerge));
     qh_fprintf(qh, qh->ferr, 8015, "\n\nCurrent summary is:\n");
       qh_printsummary(qh, qh->ferr);
   }
   if (qh->hull_dim <= 4) {
     i= 0;
     if (qh->RANDOMdist) {
       gmcoord= qh->gm_matrix;
       FOREACHvertex_(facet->vertices) {
         qh->gm_row[i++]= gmcoord;
         coord= vertex->point;
         for (k=qh->hull_dim; k--; )
           *(gmcoord++)= *coord++ * qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
       }
     }else {
       FOREACHvertex_(facet->vertices)
        qh->gm_row[i++]= vertex->point;
     }
     qh_sethyperplane_det(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
                 facet->normal, &facet->offset, &nearzero);
   }
   if (qh->hull_dim > 4 || nearzero) {
     i= 0;
     gmcoord= qh->gm_matrix;
     FOREACHvertex_(facet->vertices) {
       if (vertex->point != point0) {
         qh->gm_row[i++]= gmcoord;
         coord= vertex->point;
         point= point0;
         for (k=qh->hull_dim; k--; )
           *(gmcoord++)= *coord++ - *point++;
       }
     }
     qh->gm_row[i]= gmcoord;  /* for areasimplex */
     if (qh->RANDOMdist) {
       gmcoord= qh->gm_matrix;
       for (i=qh->hull_dim-1; i--; ) {
         for (k=qh->hull_dim; k--; )
           *(gmcoord++) *= qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
       }
     }
     qh_sethyperplane_gauss(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
                 facet->normal, &facet->offset, &nearzero);
     if (nearzero) {
       if (qh_orientoutside(qh, facet)) {
         trace0((qh, qh->ferr, 2, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh->furthest_id));
       /* this is part of using Gaussian Elimination.  For example in 5-d
            1 1 1 1 0
            1 1 1 1 1
            0 0 0 1 0
            0 1 0 0 0
            1 0 0 0 0
            norm= 0.38 0.38 -0.76 0.38 0
          has a determinate of 1, but g.e. after subtracting pt. 0 has
          0's in the diagonal, even with full pivoting.  It does work
          if you subtract pt. 4 instead. */
       }
     }
   }
   facet->upperdelaunay= False;
   if (qh->DELAUNAY) {
     if (qh->UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
       if (facet->normal[qh->hull_dim -1] >= qh->ANGLEround * qh_ZEROdelaunay)
         facet->upperdelaunay= True;
     }else {
       if (facet->normal[qh->hull_dim -1] > -qh->ANGLEround * qh_ZEROdelaunay)
         facet->upperdelaunay= True;
     }
   }
   if (qh->PRINTstatistics || qh->IStracing || qh->TRACElevel || qh->JOGGLEmax < REALmax) {
     qh->old_randomdist= qh->RANDOMdist;
     qh->RANDOMdist= False;
     FOREACHvertex_(facet->vertices) {
       if (vertex->point != point0) {
         boolT istrace= False;
         zinc_(Zdiststat);
         qh_distplane(qh, vertex->point, facet, &dist);
         dist= fabs_(dist);
         zinc_(Znewvertex);
         wadd_(Wnewvertex, dist);
         if (dist > wwval_(Wnewvertexmax)) {
           wwval_(Wnewvertexmax)= dist;
           if (dist > qh->max_outside) {
             qh->max_outside= dist;  /* used by qh_maxouter(qh) */
             if (dist > qh->TRACEdist)
               istrace= True;
           }
         }else if (-dist > qh->TRACEdist)
           istrace= True;
         if (istrace) {
           qh_fprintf(qh, qh->ferr, 8016, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
                 qh_pointid(qh, vertex->point), vertex->id, dist, facet->id, qh->furthest_id);
           qh_errprint(qh, "DISTANT", facet, NULL, NULL, NULL);
         }
       }
     }
     qh->RANDOMdist= qh->old_randomdist;
   }
   if (qh->IStracing >= 3) {
     qh_fprintf(qh, qh->ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",
              facet->id, facet->offset);
     for (k=0; k < qh->hull_dim; k++)
       qh_fprintf(qh, qh->ferr, 8018, "%2.2g ", facet->normal[k]);
     qh_fprintf(qh, qh->ferr, 8019, "\n");
   }
   if (facet == qh->tracefacet)
     qh->IStracing= oldtrace;
 } /* setfacetplane */
 
 
 /*---------------------------------
 
   qh_sethyperplane_det(qh, dim, rows, point0, toporient, normal, offset, nearzero )
     given dim X dim array indexed by rows[], one row per point,
         toporient(flips all signs),
         and point0 (any row)
     set normalized hyperplane equation from oriented simplex
 
   returns:
     normal (normalized)
     offset (places point0 on the hyperplane)
     sets nearzero if hyperplane not through points
 
   notes:
     only defined for dim == 2..4
     rows[] is not modified
     solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
     see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
 
   derivation of 3-d minnorm
     Goal: all vertices V_i within qh.one_merge of hyperplane
     Plan: exactly translate the facet so that V_0 is the origin
           exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
           exactly rotate the effective perturbation to only effect n_0
              this introduces a factor of sqrt(3)
     n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
     Let M_d be the max coordinate difference
     Let M_a be the greater of M_d and the max abs. coordinate
     Let u be machine roundoff and distround be max error for distance computation
     The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
     The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
     Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
     Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d
 
   derivation of 4-d minnorm
     same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
      [if two vertices fixed on x-axis, can rotate the other two in yzw.]
     n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
      [all other terms contain at least two factors nearly zero.]
     The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
     Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
     Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
 */
 void qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
           boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
   realT maxround, dist;
   int i;
   pointT *point;
 
 
   if (dim == 2) {
     normal[0]= dY(1,0);
     normal[1]= dX(0,1);
     qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
     *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
     *nearzero= False;  /* since nearzero norm => incident points */
   }else if (dim == 3) {
     normal[0]= det2_(dY(2,0), dZ(2,0),
                      dY(1,0), dZ(1,0));
     normal[1]= det2_(dX(1,0), dZ(1,0),
                      dX(2,0), dZ(2,0));
     normal[2]= det2_(dX(2,0), dY(2,0),
                      dX(1,0), dY(1,0));
     qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
     *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
                + point0[2]*normal[2]);
     maxround= qh->DISTround;
     for (i=dim; i--; ) {
       point= rows[i];
       if (point != point0) {
         dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
                + point[2]*normal[2]);
         if (dist > maxround || dist < -maxround) {
           *nearzero= True;
           break;
         }
       }
     }
   }else if (dim == 4) {
     normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
                         dY(1,0), dZ(1,0), dW(1,0),
                         dY(3,0), dZ(3,0), dW(3,0));
     normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
                         dX(1,0), dZ(1,0), dW(1,0),
                         dX(3,0), dZ(3,0), dW(3,0));
     normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
                         dX(1,0), dY(1,0), dW(1,0),
                         dX(3,0), dY(3,0), dW(3,0));
     normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
                         dX(1,0), dY(1,0), dZ(1,0),
                         dX(3,0), dY(3,0), dZ(3,0));
     qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
     *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
                + point0[2]*normal[2] + point0[3]*normal[3]);
     maxround= qh->DISTround;
     for (i=dim; i--; ) {
       point= rows[i];
       if (point != point0) {
         dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
                + point[2]*normal[2] + point[3]*normal[3]);
         if (dist > maxround || dist < -maxround) {
           *nearzero= True;
           break;
         }
       }
     }
   }
   if (*nearzero) {
     zzinc_(Zminnorm);
     trace0((qh, qh->ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh->furthest_id));
     zzinc_(Znearlysingular);
   }
 } /* sethyperplane_det */
 
 
 /*---------------------------------
 
   qh_sethyperplane_gauss(qh, dim, rows, point0, toporient, normal, offset, nearzero )
     given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
     set normalized hyperplane equation from oriented simplex
 
   returns:
     normal (normalized)
     offset (places point0 on the hyperplane)
 
   notes:
     if nearzero
       orientation may be incorrect because of incorrect sign flips in gausselim
     solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
         or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
     i.e., N is normal to the hyperplane, and the unnormalized
         distance to [0 .. 1] is either 1 or   0
 
   design:
     perform gaussian elimination
     flip sign for negative values
     perform back substitution
     normalize result
     compute offset
 */
 void qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
                 boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
   coordT *pointcoord, *normalcoef;
   int k;
   boolT sign= toporient, nearzero2= False;
 
   qh_gausselim(qh, rows, dim-1, dim, &sign, nearzero);
   for (k=dim-1; k--; ) {
     if ((rows[k])[k] < 0)
       sign ^= 1;
   }
   if (*nearzero) {
     zzinc_(Znearlysingular);
     trace0((qh, qh->ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh->furthest_id));
     qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
   }else {
     qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
     if (nearzero2) {
       zzinc_(Znearlysingular);
       trace0((qh, qh->ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh->furthest_id));
     }
   }
   if (nearzero2)
     *nearzero= True;
   qh_normalize2(qh, normal, dim, True, NULL, NULL);
   pointcoord= point0;
   normalcoef= normal;
   *offset= -(*pointcoord++ * *normalcoef++);
   for (k=dim-1; k--; )
     *offset -= *pointcoord++ * *normalcoef++;
 } /* sethyperplane_gauss */
 
 
 
diff --git a/src/libqhullr/geom_r.h b/src/libqhullr/geom_r.h
index 3db76f6..cc571d1 100644
--- a/src/libqhullr/geom_r.h
+++ b/src/libqhullr/geom_r.h
@@ -1,176 +1,176 @@
 /*
  ---------------------------------
 
   geom_r.h
     header file for geometric routines
 
    see qh-geom.htm and geom_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/geom_r.h#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/geom_r.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFgeom
 #define qhDEFgeom 1
 
 #include "libqhull_r.h"
 
 /* ============ -macros- ======================== */
 
 /*----------------------------------
 
   fabs_(a)
     returns the absolute value of a
 */
 #define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
 
 /*----------------------------------
 
   fmax_(a,b)
     returns the maximum value of a and b
 */
 #define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
 
 /*----------------------------------
 
   fmin_(a,b)
     returns the minimum value of a and b
 */
 #define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
 
 /*----------------------------------
 
   maximize_(maxval, val)
     set maxval to val if val is greater than maxval
 */
 #define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); }
 
 /*----------------------------------
 
   minimize_(minval, val)
     set minval to val if val is less than minval
 */
 #define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); }
 
 /*----------------------------------
 
   det2_(a1, a2,
         b1, b2)
 
     compute a 2-d determinate
 */
 #define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
 
 /*----------------------------------
 
   det3_(a1, a2, a3,
        b1, b2, b3,
        c1, c2, c3)
 
     compute a 3-d determinate
 */
 #define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
                 - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
 
 /*----------------------------------
 
   dX( p1, p2 )
   dY( p1, p2 )
   dZ( p1, p2 )
 
     given two indices into rows[],
 
     compute the difference between X, Y, or Z coordinates
 */
 #define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
 #define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
 #define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
 #define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
 
 /*============= prototypes in alphabetical order, infrequent at end ======= */
 
 void    qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
 void    qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist);
 facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
                      boolT bestoutside, boolT isnewfacets, boolT noupper,
                      realT *dist, boolT *isoutside, int *numpart);
 facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT *point,
                      facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
 facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet, realT *dist,
                      boolT bestoutside, boolT *isoutside, int *numpart);
 void    qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
 realT   qh_getangle(qhT *qh, pointT *vect1, pointT *vect2);
 pointT *qh_getcenter(qhT *qh, setT *vertices);
 pointT *qh_getcentrum(qhT *qh, facetT *facet);
 realT   qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
 void    qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient);
 void    qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
             realT *minnorm, boolT *ismin);
 pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist);
 
 void    qh_setfacetplane(qhT *qh, facetT *newfacets);
 void    qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
               boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
 void    qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
              boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
 boolT   qh_sharpnewfacets(qhT *qh);
 
 /*========= infrequently used code in geom2_r.c =============*/
 
 coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension);
 void    qh_crossproduct(qhT *qh, int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
 realT   qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero);
 realT   qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension);
 void    qh_detroundoff(qhT *qh);
 realT   qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero);
 realT   qh_distnorm(qhT *qh, int dim, pointT *point, pointT *normal, realT *offsetp);
 realT   qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs);
 realT   qh_divzero(qhT *qh, realT numer, realT denom, realT mindenom1, boolT *zerodiv);
 realT   qh_facetarea(qhT *qh, facetT *facet);
 realT   qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,
           vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
 pointT *qh_facetcenter(qhT *qh, setT *vertices);
 facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
 void    qh_getarea(qhT *qh, facetT *facetlist);
 boolT   qh_gram_schmidt(qhT *qh, int dim, realT **rows);
 boolT   qh_inthresholds(qhT *qh, coordT *normal, realT *angle);
 void    qh_joggleinput(qhT *qh);
 realT  *qh_maxabsval(qhT *qh, realT *normal, int dim);
 setT   *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension);
 realT   qh_maxouter(qhT *qh);
 void    qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
 realT   qh_minabsval(qhT *qh, realT *normal, int dim);
 int     qh_mindiff(qhT *qh, realT *vecA, realT *vecB, int dim);
 boolT   qh_orientoutside(qhT *qh, facetT *facet);
 void    qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
 coordT  qh_pointdist(qhT *qh, pointT *point1, pointT *point2, int dim);
 void    qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol);
 void    qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points);
 void    qh_projectinput(qhT *qh);
 void    qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,
              int numpoints, int dim, realT *newpoints, int newdim);
 void    qh_rotateinput(qhT *qh, realT **rows);
 void    qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **rows);
 void    qh_scaleinput(qhT *qh);
 void    qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,
                    coordT high, coordT newhigh);
 void    qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,
                 realT *newlows, realT *newhighs);
 boolT   qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,
               coordT *normal, coordT *offset, coordT *feasible);
 coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible);
 pointT *qh_voronoi_center(qhT *qh, int dim, setT *points);
 
 #endif /* qhDEFgeom */
 
 
 
diff --git a/src/libqhullr/global_r.c b/src/libqhullr/global_r.c
index 1b9bdf7..61d20b6 100644
--- a/src/libqhullr/global_r.c
+++ b/src/libqhullr/global_r.c
@@ -1,2007 +1,2007 @@
 
 /*
  ---------------------------------
 
    global_r.c
    initializes all the globals of the qhull application
 
    see README
 
    see libqhull_r.h for qh.globals and function prototypes
 
    see qhull_ra.h for internal functions
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/global_r.c#9 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/global_r.c#10 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
  */
 
 #include "qhull_ra.h"
 
 /*========= qh->definition -- globals defined in libqhull_r.h =======================*/
 
 /*----------------------------------
 
   qh_version
     version string by year and date
 
     the revision increases on code changes only
 
   notes:
     change date:    Changes.txt, Announce.txt, index.htm, README.txt,
                     qhull-news.html, Eudora signatures, CMakeLists.txt
     change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt
     change year:    Copying.txt
     check download size
     recompile user_eg_r.c, rbox_r.c, libqhull_r.c, qconvex_r.c, qdelaun_r.c qvoronoi_r.c, qhalf_r.c, testqset_r.c
 */
 
 const char *qh_version = "2012.1 2012/02/18";
 
 /*---------------------------------
 
   qh_appendprint(qh, printFormat )
     append printFormat to qh.PRINTout unless already defined
 */
 void qh_appendprint(qhT *qh, qh_PRINT format) {
   int i;
 
   for (i=0; i < qh_PRINTEND; i++) {
     if (qh->PRINTout[i] == format && format != qh_PRINTqhull)
       break;
     if (!qh->PRINTout[i]) {
       qh->PRINTout[i]= format;
       break;
     }
   }
 } /* appendprint */
 
 /*---------------------------------
 
   qh_checkflags(qh, commandStr, hiddenFlags )
     errors if commandStr contains hiddenFlags
     hiddenFlags starts and ends with a space and is space deliminated (checked)
 
   notes:
     ignores first word (e.g., "qconvex i")
     use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
 
   see:
     qh_initflags() initializes Qhull according to commandStr
 */
 void qh_checkflags(qhT *qh, char *command, char *hiddenflags) {
   char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */
   char key, opt, prevopt;
   char chkkey[]= "   ";
   char chkopt[]=  "    ";
   char chkopt2[]= "     ";
   boolT waserr= False;
 
   if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
     qh_fprintf(qh, qh->ferr, 6026, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (strpbrk(hiddenflags, ",\n\r\t")) {
     qh_fprintf(qh, qh->ferr, 6027, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   while (*s && !isspace(*s))  /* skip program name */
     s++;
   while (*s) {
     while (*s && isspace(*s))
       s++;
     if (*s == '-')
       s++;
     if (!*s)
       break;
     key = *s++;
     chkerr = NULL;
     if (key == 'T' && (*s == 'I' || *s == 'O')) {  /* TI or TO 'file name' */
       s= qh_skipfilename(qh, ++s);
       continue;
     }
     chkkey[1]= key;
     if (strstr(hiddenflags, chkkey)) {
       chkerr= chkkey;
     }else if (isupper(key)) {
       opt= ' ';
       prevopt= ' ';
       chkopt[1]= key;
       chkopt2[1]= key;
       while (!chkerr && *s && !isspace(*s)) {
         opt= *s++;
         if (isalpha(opt)) {
           chkopt[2]= opt;
           if (strstr(hiddenflags, chkopt))
             chkerr= chkopt;
           if (prevopt != ' ') {
             chkopt2[2]= prevopt;
             chkopt2[3]= opt;
             if (strstr(hiddenflags, chkopt2))
               chkerr= chkopt2;
           }
         }else if (key == 'Q' && isdigit(opt) && prevopt != 'b'
               && (prevopt == ' ' || islower(prevopt))) {
             chkopt[2]= opt;
             if (strstr(hiddenflags, chkopt))
               chkerr= chkopt;
         }else {
           qh_strtod(s-1, &t);
           if (s < t)
             s= t;
         }
         prevopt= opt;
       }
     }
     if (chkerr) {
       *chkerr= '\'';
       chkerr[strlen(chkerr)-1]=  '\'';
       qh_fprintf(qh, qh->ferr, 6029, "qhull error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
       waserr= True;
     }
   }
   if (waserr)
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
 } /* checkflags */
 
 /*---------------------------------
 
   qh_clear_outputflags(qh)
     Clear output flags for QhullPoints
 */
 void qh_clear_outputflags(qhT *qh) {
   int i,k;
 
   qh->ANNOTATEoutput= False;
   qh->DOintersections= False;
   qh->DROPdim= -1;
   qh->FORCEoutput= False;
   qh->GETarea= False;
   qh->GOODpoint= 0;
   qh->GOODpointp= NULL;
   qh->GOODthreshold= False;
   qh->GOODvertex= 0;
   qh->GOODvertexp= NULL;
   qh->IStracing= 0;
   qh->KEEParea= False;
   qh->KEEPmerge= False;
   qh->KEEPminArea= REALmax;
   qh->PRINTcentrums= False;
   qh->PRINTcoplanar= False;
   qh->PRINTdots= False;
   qh->PRINTgood= False;
   qh->PRINTinner= False;
   qh->PRINTneighbors= False;
   qh->PRINTnoplanes= False;
   qh->PRINToptions1st= False;
   qh->PRINTouter= False;
   qh->PRINTprecision= True;
   qh->PRINTridges= False;
   qh->PRINTspheres= False;
   qh->PRINTstatistics= False;
   qh->PRINTsummary= False;
   qh->PRINTtransparent= False;
   qh->SPLITthresholds= False;
   qh->TRACElevel= 0;
   qh->TRInormals= False;
   qh->USEstdout= False;
   qh->VERIFYoutput= False;
   for (k=qh->input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_ouputflags */
     qh->lower_threshold[k]= -REALmax;
     qh->upper_threshold[k]= REALmax;
     qh->lower_bound[k]= -REALmax;
     qh->upper_bound[k]= REALmax;
   }
 
   for (i=0; i < qh_PRINTEND; i++) {
     qh->PRINTout[i]= qh_PRINTnone;
   }
 
   if (!qh->qhull_commandsiz2)
       qh->qhull_commandsiz2= (int)strlen(qh->qhull_command); /* WARN64 */
   else {
       qh->qhull_command[qh->qhull_commandsiz2]= '\0';
   }
   if (!qh->qhull_optionsiz2)
     qh->qhull_optionsiz2= (int)strlen(qh->qhull_options);  /* WARN64 */
   else {
     qh->qhull_options[qh->qhull_optionsiz2]= '\0';
     qh->qhull_optionlen= qh_OPTIONline;  /* start a new line */
   }
 } /* clear_outputflags */
 
 /*---------------------------------
 
   qh_clock()
     return user CPU time in 100ths (qh_SECtick)
     only defined for qh_CLOCKtype == 2
 
   notes:
     use first value to determine time 0
     from Stevens '92 8.15
 */
 unsigned long qh_clock(qhT *qh) {
 
 #if (qh_CLOCKtype == 2)
   struct tms time;
   static long clktck;  /* initialized first call */
   double ratio, cpu;
   unsigned long ticks;
 
   if (!clktck) {
     if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {
       qh_fprintf(qh, qh->ferr, 6030, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user.h\n");
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }
   }
   if (times(&time) == -1) {
     qh_fprintf(qh, qh->ferr, 6031, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user.h\n");
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   ratio= qh_SECticks / (double)clktck;
   ticks= time.tms_utime * ratio;
   return ticks;
 #else
   qh_fprintf(qh, qh->ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");
   qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* never returns */
   return 0;
 #endif
 } /* clock */
 
 /*---------------------------------
 
   qh_freebuffers()
     free up global memory buffers
 
   notes:
     must match qh_initbuffers()
 */
 void qh_freebuffers(qhT *qh) {
 
   trace5((qh, qh->ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));
   /* allocated by qh_initqhull_buffers */
   qh_memfree(qh, qh->NEARzero, qh->hull_dim * sizeof(realT));
   qh_memfree(qh, qh->lower_threshold, (qh->input_dim+1) * sizeof(realT));
   qh_memfree(qh, qh->upper_threshold, (qh->input_dim+1) * sizeof(realT));
   qh_memfree(qh, qh->lower_bound, (qh->input_dim+1) * sizeof(realT));
   qh_memfree(qh, qh->upper_bound, (qh->input_dim+1) * sizeof(realT));
   qh_memfree(qh, qh->gm_matrix, (qh->hull_dim+1) * qh->hull_dim * sizeof(coordT));
   qh_memfree(qh, qh->gm_row, (qh->hull_dim+1) * sizeof(coordT *));
   qh->NEARzero= qh->lower_threshold= qh->upper_threshold= NULL;
   qh->lower_bound= qh->upper_bound= NULL;
   qh->gm_matrix= NULL;
   qh->gm_row= NULL;
   qh_setfree(qh, &qh->other_points);
   qh_setfree(qh, &qh->del_vertices);
   qh_setfree(qh, &qh->coplanarfacetset);
   if (qh->line)                /* allocated by qh_readinput, freed if no error */
     qh_free(qh->line);
   if (qh->half_space)
     qh_free(qh->half_space);
   if (qh->temp_malloc)
     qh_free(qh->temp_malloc);
   if (qh->feasible_point)      /* allocated by qh_readfeasible */
     qh_free(qh->feasible_point);
   if (qh->feasible_string)     /* allocated by qh_initflags */
     qh_free(qh->feasible_string);
   qh->line= qh->feasible_string= NULL;
   qh->half_space= qh->feasible_point= qh->temp_malloc= NULL;
   /* usually allocated by qh_readinput */
   if (qh->first_point && qh->POINTSmalloc) {
     qh_free(qh->first_point);
     qh->first_point= NULL;
   }
   if (qh->input_points && qh->input_malloc) { /* set by qh_joggleinput */
     qh_free(qh->input_points);
     qh->input_points= NULL;
   }
   trace5((qh, qh->ferr, 5002, "qh_freebuffers: finished\n"));
 } /* freebuffers */
 
 
 /*---------------------------------
 
   qh_freebuild(qh, allmem )
     free global memory used by qh_initbuild and qh_buildhull
     if !allmem,
       does not free short memory (e.g., facetT, freed by qh_memfreeshort)
 
   design:
     free centrums
     free each vertex
     mark unattached ridges
     for each facet
       free ridges
       free outside set, coplanar set, neighbor set, ridge set, vertex set
       free facet
     free hash table
     free interior point
     free merge set
     free temporary sets
 */
 void qh_freebuild(qhT *qh, boolT allmem) {
   facetT *facet;
   vertexT *vertex;
   ridgeT *ridge, **ridgep;
   mergeT *merge, **mergep;
 
   trace1((qh, qh->ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
   if (qh->del_vertices)
     qh_settruncate(qh, qh->del_vertices, 0);
   if (allmem) {
     while ((vertex= qh->vertex_list)) {
       if (vertex->next)
         qh_delvertex(qh, vertex);
       else {
         qh_memfree(qh, vertex, (int)sizeof(vertexT));
         qh->newvertex_list= qh->vertex_list= NULL;
       }
     }
   }else if (qh->VERTEXneighbors) {
     FORALLvertices
       qh_setfreelong(qh, &(vertex->neighbors));
   }
   qh->VERTEXneighbors= False;
   qh->GOODclosest= NULL;
   if (allmem) {
     FORALLfacets {
       FOREACHridge_(facet->ridges)
         ridge->seen= False;
     }
     FORALLfacets {
       if (facet->visible) {
         FOREACHridge_(facet->ridges) {
           if (!otherfacet_(ridge, facet)->visible)
             ridge->seen= True;  /* an unattached ridge */
         }
       }
     }
     while ((facet= qh->facet_list)) {
       FOREACHridge_(facet->ridges) {
         if (ridge->seen) {
           qh_setfree(qh, &(ridge->vertices));
           qh_memfree(qh, ridge, (int)sizeof(ridgeT));
         }else
           ridge->seen= True;
       }
       qh_setfree(qh, &(facet->outsideset));
       qh_setfree(qh, &(facet->coplanarset));
       qh_setfree(qh, &(facet->neighbors));
       qh_setfree(qh, &(facet->ridges));
       qh_setfree(qh, &(facet->vertices));
       if (facet->next)
         qh_delfacet(qh, facet);
       else {
         qh_memfree(qh, facet, (int)sizeof(facetT));
         qh->visible_list= qh->newfacet_list= qh->facet_list= NULL;
       }
     }
   }else {
     FORALLfacets {
       qh_setfreelong(qh, &(facet->outsideset));
       qh_setfreelong(qh, &(facet->coplanarset));
       if (!facet->simplicial) {
         qh_setfreelong(qh, &(facet->neighbors));
         qh_setfreelong(qh, &(facet->ridges));
         qh_setfreelong(qh, &(facet->vertices));
       }
     }
   }
   qh_setfree(qh, &(qh->hash_table));
   qh_memfree(qh, qh->interior_point, qh->normal_size);
   qh->interior_point= NULL;
   FOREACHmerge_(qh->facet_mergeset)  /* usually empty */
     qh_memfree(qh, merge, (int)sizeof(mergeT));
   qh->facet_mergeset= NULL;  /* temp set */
   qh->degen_mergeset= NULL;  /* temp set */
   qh_settempfree_all(qh);
 } /* freebuild */
 
 /*---------------------------------
 
   qh_freeqhull(qh, allmem )
 
   free global memory
   if !allmem,
     does not free short memory (freed by qh_memfreeshort)
 
 notes:
   sets qh.NOerrexit in case caller forgets to
   Does not throw errors
 
 see:
   see qh_initqhull_start2()
 
 design:
   free global and temporary memory from qh_initbuild and qh_buildhull
   free buffers
   free statistics
 */
 void qh_freeqhull(qhT *qh, boolT allmem) {
 
   qh->NOerrexit= True;  /* no more setjmp since called at exit and ~QhullQh */
   trace1((qh, qh->ferr, 1006, "qh_freeqhull: free global memory\n"));
   qh_freebuild(qh, allmem);
   qh_freebuffers(qh);
   /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */
   memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));
   qh->NOerrexit= True;
 } /* freeqhull2 */
 
 /*---------------------------------
 
   qh_init_A(qh, infile, outfile, errfile, argc, argv )
     initialize memory and stdio files
     convert input options to option string (qh.qhull_command)
 
   notes:
     infile may be NULL if qh_readpoints() is not called
 
     errfile should always be defined.  It is used for reporting
     errors.  outfile is used for output and format options.
 
     argc/argv may be 0/NULL
 
     called before error handling initialized
     qh_errexit() may not be used
 */
 void qh_init_A(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
   qh_meminit(qh, errfile);
   qh_initqhull_start(qh, infile, outfile, errfile);
   qh_init_qhull_command(qh, argc, argv);
 } /* init_A */
 
 /*---------------------------------
 
   qh_init_B(qh, points, numpoints, dim, ismalloc )
     initialize globals for points array
 
     points has numpoints dim-dimensional points
       points[0] is the first coordinate of the first point
       points[1] is the second coordinate of the first point
       points[dim] is the first coordinate of the second point
 
     ismalloc=True
       Qhull will call qh_free(points) on exit or input transformation
     ismalloc=False
       Qhull will allocate a new point array if needed for input transformation
 
     qh.qhull_command
       is the option string.
       It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags
 
   returns:
     if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
       projects the input to a new point array
 
         if qh.DELAUNAY,
           qh.hull_dim is increased by one
         if qh.ATinfinity,
           qh_projectinput adds point-at-infinity for Delaunay tri.
 
     if qh.SCALEinput
       changes the upper and lower bounds of the input, see qh_scaleinput(qh)
 
     if qh.ROTATEinput
       rotates the input by a random rotation, see qh_rotateinput()
       if qh.DELAUNAY
         rotates about the last coordinate
 
   notes:
     called after points are defined
     qh_errexit() may be used
 */
 void qh_init_B(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {
   qh_initqhull_globals(qh, points, numpoints, dim, ismalloc);
   if (qh->qhmem.LASTsize == 0)
     qh_initqhull_mem(qh);
   /* mem_r.c and qset_r.c are initialized */
   qh_initqhull_buffers(qh);
   qh_initthresholds(qh, qh->qhull_command);
   if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay))
     qh_projectinput(qh);
   if (qh->SCALEinput)
     qh_scaleinput(qh);
   if (qh->ROTATErandom >= 0) {
     qh_randommatrix(qh, qh->gm_matrix, qh->hull_dim, qh->gm_row);
     if (qh->DELAUNAY) {
       int k, lastk= qh->hull_dim-1;
       for (k=0; k < lastk; k++) {
         qh->gm_row[k][lastk]= 0.0;
         qh->gm_row[lastk][k]= 0.0;
       }
       qh->gm_row[lastk][lastk]= 1.0;
     }
     qh_gram_schmidt(qh, qh->hull_dim, qh->gm_row);
     qh_rotateinput(qh, qh->gm_row);
   }
 } /* init_B */
 
 /*---------------------------------
 
   qh_init_qhull_command(qh, argc, argv )
     build qh.qhull_command from argc/argv
 
   returns:
     a space-delimited string of options (just as typed)
 
   notes:
     makes option string easy to input and output
 
     argc/argv may be 0/NULL
 */
 void qh_init_qhull_command(qhT *qh, int argc, char *argv[]) {
 
   if (!qh_argv_to_command(argc, argv, qh->qhull_command, (int)sizeof(qh->qhull_command))){
     /* Assumes qh.ferr is defined. */
     qh_fprintf(qh, qh->ferr, 6033, "qhull input error: more than %d characters in command line\n",
           (int)sizeof(qh->qhull_command));
     qh_exit(qh_ERRinput);  /* error reported, can not use qh_errexit */
   }
 } /* init_qhull_command */
 
 /*---------------------------------
 
   qh_initflags(qh, commandStr )
     set flags and initialized constants from commandStr
 
   returns:
     sets qh.qhull_command to command if needed
 
   notes:
     ignores first word (e.g., "qhull d")
     use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
 
   see:
     qh_initthresholds() continues processing of 'Pdn' and 'PDn'
     'prompt' in unix_r.c for documentation
 
   design:
     for each space-deliminated option group
       if top-level option
         check syntax
         append approriate option to option string
         set appropriate global variable or append printFormat to print options
       else
         for each sub-option
           check syntax
           append approriate option to option string
           set appropriate global variable or append printFormat to print options
 */
 void qh_initflags(qhT *qh, char *command) {
   int k, i, lastproject;
   char *s= command, *t, *prev_s, *start, key;
   boolT isgeom= False, wasproject;
   realT r;
 
   if (command <= &qh->qhull_command[0] || command > &qh->qhull_command[0] + sizeof(qh->qhull_command)) {
     if (command != &qh->qhull_command[0]) {
       *qh->qhull_command= '\0';
       strncat(qh->qhull_command, command, sizeof(qh->qhull_command)-strlen(qh->qhull_command)-1);
     }
     while (*s && !isspace(*s))  /* skip program name */
       s++;
   }
   while (*s) {
     while (*s && isspace(*s))
       s++;
     if (*s == '-')
       s++;
     if (!*s)
       break;
     prev_s= s;
     switch (*s++) {
     case 'd':
       qh_option(qh, "delaunay", NULL, NULL);
       qh->DELAUNAY= True;
       break;
     case 'f':
       qh_option(qh, "facets", NULL, NULL);
       qh_appendprint(qh, qh_PRINTfacets);
       break;
     case 'i':
       qh_option(qh, "incidence", NULL, NULL);
       qh_appendprint(qh, qh_PRINTincidences);
       break;
     case 'm':
       qh_option(qh, "mathematica", NULL, NULL);
       qh_appendprint(qh, qh_PRINTmathematica);
       break;
     case 'n':
       qh_option(qh, "normals", NULL, NULL);
       qh_appendprint(qh, qh_PRINTnormals);
       break;
     case 'o':
       qh_option(qh, "offFile", NULL, NULL);
       qh_appendprint(qh, qh_PRINToff);
       break;
     case 'p':
       qh_option(qh, "points", NULL, NULL);
       qh_appendprint(qh, qh_PRINTpoints);
       break;
     case 's':
       qh_option(qh, "summary", NULL, NULL);
       qh->PRINTsummary= True;
       break;
     case 'v':
       qh_option(qh, "voronoi", NULL, NULL);
       qh->VORONOI= True;
       qh->DELAUNAY= True;
       break;
     case 'A':
       if (!isdigit(*s) && *s != '.' && *s != '-')
         qh_fprintf(qh, qh->ferr, 7002, "qhull warning: no maximum cosine angle given for option 'An'.  Ignored.\n");
       else {
         if (*s == '-') {
           qh->premerge_cos= -qh_strtod(s, &s);
           qh_option(qh, "Angle-premerge-", NULL, &qh->premerge_cos);
           qh->PREmerge= True;
         }else {
           qh->postmerge_cos= qh_strtod(s, &s);
           qh_option(qh, "Angle-postmerge", NULL, &qh->postmerge_cos);
           qh->POSTmerge= True;
         }
         qh->MERGING= True;
       }
       break;
     case 'C':
       if (!isdigit(*s) && *s != '.' && *s != '-')
         qh_fprintf(qh, qh->ferr, 7003, "qhull warning: no centrum radius given for option 'Cn'.  Ignored.\n");
       else {
         if (*s == '-') {
           qh->premerge_centrum= -qh_strtod(s, &s);
           qh_option(qh, "Centrum-premerge-", NULL, &qh->premerge_centrum);
           qh->PREmerge= True;
         }else {
           qh->postmerge_centrum= qh_strtod(s, &s);
           qh_option(qh, "Centrum-postmerge", NULL, &qh->postmerge_centrum);
           qh->POSTmerge= True;
         }
         qh->MERGING= True;
       }
       break;
     case 'E':
       if (*s == '-')
         qh_fprintf(qh, qh->ferr, 7004, "qhull warning: negative maximum roundoff given for option 'An'.  Ignored.\n");
       else if (!isdigit(*s))
         qh_fprintf(qh, qh->ferr, 7005, "qhull warning: no maximum roundoff given for option 'En'.  Ignored.\n");
       else {
         qh->DISTround= qh_strtod(s, &s);
         qh_option(qh, "Distance-roundoff", NULL, &qh->DISTround);
         qh->SETroundoff= True;
       }
       break;
     case 'H':
       start= s;
       qh->HALFspace= True;
       qh_strtod(s, &t);
       while (t > s)  {
         if (*t && !isspace(*t)) {
           if (*t == ',')
             t++;
           else
             qh_fprintf(qh, qh->ferr, 7006, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n");
         }
         s= t;
         qh_strtod(s, &t);
       }
       if (start < t) {
         if (!(qh->feasible_string= (char*)calloc((size_t)(t-start+1), (size_t)1))) {
           qh_fprintf(qh, qh->ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");
           qh_errexit(qh, qh_ERRmem, NULL, NULL);
         }
         strncpy(qh->feasible_string, start, (size_t)(t-start));
         qh_option(qh, "Halfspace-about", NULL, NULL);
         qh_option(qh, qh->feasible_string, NULL, NULL);
       }else
         qh_option(qh, "Halfspace", NULL, NULL);
       break;
     case 'R':
       if (!isdigit(*s))
         qh_fprintf(qh, qh->ferr, 7007, "qhull warning: missing random perturbation for option 'Rn'.  Ignored\n");
       else {
         qh->RANDOMfactor= qh_strtod(s, &s);
         qh_option(qh, "Random_perturb", NULL, &qh->RANDOMfactor);
         qh->RANDOMdist= True;
       }
       break;
     case 'V':
       if (!isdigit(*s) && *s != '-')
         qh_fprintf(qh, qh->ferr, 7008, "qhull warning: missing visible distance for option 'Vn'.  Ignored\n");
       else {
         qh->MINvisible= qh_strtod(s, &s);
         qh_option(qh, "Visible", NULL, &qh->MINvisible);
       }
       break;
     case 'U':
       if (!isdigit(*s) && *s != '-')
         qh_fprintf(qh, qh->ferr, 7009, "qhull warning: missing coplanar distance for option 'Un'.  Ignored\n");
       else {
         qh->MAXcoplanar= qh_strtod(s, &s);
         qh_option(qh, "U-coplanar", NULL, &qh->MAXcoplanar);
       }
       break;
     case 'W':
       if (*s == '-')
         qh_fprintf(qh, qh->ferr, 7010, "qhull warning: negative outside width for option 'Wn'.  Ignored.\n");
       else if (!isdigit(*s))
         qh_fprintf(qh, qh->ferr, 7011, "qhull warning: missing outside width for option 'Wn'.  Ignored\n");
       else {
         qh->MINoutside= qh_strtod(s, &s);
         qh_option(qh, "W-outside", NULL, &qh->MINoutside);
         qh->APPROXhull= True;
       }
       break;
     /************  sub menus ***************/
     case 'F':
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'a':
           qh_option(qh, "Farea", NULL, NULL);
           qh_appendprint(qh, qh_PRINTarea);
           qh->GETarea= True;
           break;
         case 'A':
           qh_option(qh, "FArea-total", NULL, NULL);
           qh->GETarea= True;
           break;
         case 'c':
           qh_option(qh, "Fcoplanars", NULL, NULL);
           qh_appendprint(qh, qh_PRINTcoplanars);
           break;
         case 'C':
           qh_option(qh, "FCentrums", NULL, NULL);
           qh_appendprint(qh, qh_PRINTcentrums);
           break;
         case 'd':
           qh_option(qh, "Fd-cdd-in", NULL, NULL);
           qh->CDDinput= True;
           break;
         case 'D':
           qh_option(qh, "FD-cdd-out", NULL, NULL);
           qh->CDDoutput= True;
           break;
         case 'F':
           qh_option(qh, "FFacets-xridge", NULL, NULL);
           qh_appendprint(qh, qh_PRINTfacets_xridge);
           break;
         case 'i':
           qh_option(qh, "Finner", NULL, NULL);
           qh_appendprint(qh, qh_PRINTinner);
           break;
         case 'I':
           qh_option(qh, "FIDs", NULL, NULL);
           qh_appendprint(qh, qh_PRINTids);
           break;
         case 'm':
           qh_option(qh, "Fmerges", NULL, NULL);
           qh_appendprint(qh, qh_PRINTmerges);
           break;
         case 'M':
           qh_option(qh, "FMaple", NULL, NULL);
           qh_appendprint(qh, qh_PRINTmaple);
           break;
         case 'n':
           qh_option(qh, "Fneighbors", NULL, NULL);
           qh_appendprint(qh, qh_PRINTneighbors);
           break;
         case 'N':
           qh_option(qh, "FNeighbors-vertex", NULL, NULL);
           qh_appendprint(qh, qh_PRINTvneighbors);
           break;
         case 'o':
           qh_option(qh, "Fouter", NULL, NULL);
           qh_appendprint(qh, qh_PRINTouter);
           break;
         case 'O':
           if (qh->PRINToptions1st) {
             qh_option(qh, "FOptions", NULL, NULL);
             qh_appendprint(qh, qh_PRINToptions);
           }else
             qh->PRINToptions1st= True;
           break;
         case 'p':
           qh_option(qh, "Fpoint-intersect", NULL, NULL);
           qh_appendprint(qh, qh_PRINTpointintersect);
           break;
         case 'P':
           qh_option(qh, "FPoint-nearest", NULL, NULL);
           qh_appendprint(qh, qh_PRINTpointnearest);
           break;
         case 'Q':
           qh_option(qh, "FQhull", NULL, NULL);
           qh_appendprint(qh, qh_PRINTqhull);
           break;
         case 's':
           qh_option(qh, "Fsummary", NULL, NULL);
           qh_appendprint(qh, qh_PRINTsummary);
           break;
         case 'S':
           qh_option(qh, "FSize", NULL, NULL);
           qh_appendprint(qh, qh_PRINTsize);
           qh->GETarea= True;
           break;
         case 't':
           qh_option(qh, "Ftriangles", NULL, NULL);
           qh_appendprint(qh, qh_PRINTtriangles);
           break;
         case 'v':
           /* option set in qh_initqhull_globals */
           qh_appendprint(qh, qh_PRINTvertices);
           break;
         case 'V':
           qh_option(qh, "FVertex-average", NULL, NULL);
           qh_appendprint(qh, qh_PRINTaverage);
           break;
         case 'x':
           qh_option(qh, "Fxtremes", NULL, NULL);
           qh_appendprint(qh, qh_PRINTextremes);
           break;
         default:
           s--;
           qh_fprintf(qh, qh->ferr, 7012, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'G':
       isgeom= True;
       qh_appendprint(qh, qh_PRINTgeom);
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'a':
           qh_option(qh, "Gall-points", NULL, NULL);
           qh->PRINTdots= True;
           break;
         case 'c':
           qh_option(qh, "Gcentrums", NULL, NULL);
           qh->PRINTcentrums= True;
           break;
         case 'h':
           qh_option(qh, "Gintersections", NULL, NULL);
           qh->DOintersections= True;
           break;
         case 'i':
           qh_option(qh, "Ginner", NULL, NULL);
           qh->PRINTinner= True;
           break;
         case 'n':
           qh_option(qh, "Gno-planes", NULL, NULL);
           qh->PRINTnoplanes= True;
           break;
         case 'o':
           qh_option(qh, "Gouter", NULL, NULL);
           qh->PRINTouter= True;
           break;
         case 'p':
           qh_option(qh, "Gpoints", NULL, NULL);
           qh->PRINTcoplanar= True;
           break;
         case 'r':
           qh_option(qh, "Gridges", NULL, NULL);
           qh->PRINTridges= True;
           break;
         case 't':
           qh_option(qh, "Gtransparent", NULL, NULL);
           qh->PRINTtransparent= True;
           break;
         case 'v':
           qh_option(qh, "Gvertices", NULL, NULL);
           qh->PRINTspheres= True;
           break;
         case 'D':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 6035, "qhull input error: missing dimension for option 'GDn'\n");
           else {
             if (qh->DROPdim >= 0)
               qh_fprintf(qh, qh->ferr, 7013, "qhull warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
                    qh->DROPdim);
             qh->DROPdim= qh_strtol(s, &s);
             qh_option(qh, "GDrop-dim", &qh->DROPdim, NULL);
           }
           break;
         default:
           s--;
           qh_fprintf(qh, qh->ferr, 7014, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'P':
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'd': case 'D':  /* see qh_initthresholds() */
           key= s[-1];
           i= qh_strtol(s, &s);
           r= 0;
           if (*s == ':') {
             s++;
             r= qh_strtod(s, &s);
           }
           if (key == 'd')
             qh_option(qh, "Pdrop-facets-dim-less", &i, &r);
           else
             qh_option(qh, "PDrop-facets-dim-more", &i, &r);
           break;
         case 'g':
           qh_option(qh, "Pgood-facets", NULL, NULL);
           qh->PRINTgood= True;
           break;
         case 'G':
           qh_option(qh, "PGood-facet-neighbors", NULL, NULL);
           qh->PRINTneighbors= True;
           break;
         case 'o':
           qh_option(qh, "Poutput-forced", NULL, NULL);
           qh->FORCEoutput= True;
           break;
         case 'p':
           qh_option(qh, "Pprecision-ignore", NULL, NULL);
           qh->PRINTprecision= False;
           break;
         case 'A':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 6036, "qhull input error: missing facet count for keep area option 'PAn'\n");
           else {
             qh->KEEParea= qh_strtol(s, &s);
             qh_option(qh, "PArea-keep", &qh->KEEParea, NULL);
             qh->GETarea= True;
           }
           break;
         case 'F':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 6037, "qhull input error: missing facet area for option 'PFn'\n");
           else {
             qh->KEEPminArea= qh_strtod(s, &s);
             qh_option(qh, "PFacet-area-keep", NULL, &qh->KEEPminArea);
             qh->GETarea= True;
           }
           break;
         case 'M':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 6038, "qhull input error: missing merge count for option 'PMn'\n");
           else {
             qh->KEEPmerge= qh_strtol(s, &s);
             qh_option(qh, "PMerge-keep", &qh->KEEPmerge, NULL);
           }
           break;
         default:
           s--;
           qh_fprintf(qh, qh->ferr, 7015, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'Q':
       lastproject= -1;
       while (*s && !isspace(*s)) {
         switch (*s++) {
         case 'b': case 'B':  /* handled by qh_initthresholds */
           key= s[-1];
           if (key == 'b' && *s == 'B') {
             s++;
             r= qh_DEFAULTbox;
             qh->SCALEinput= True;
             qh_option(qh, "QbBound-unit-box", NULL, &r);
             break;
           }
           if (key == 'b' && *s == 'b') {
             s++;
             qh->SCALElast= True;
             qh_option(qh, "Qbbound-last", NULL, NULL);
             break;
           }
           k= qh_strtol(s, &s);
           r= 0.0;
           wasproject= False;
           if (*s == ':') {
             s++;
             if ((r= qh_strtod(s, &s)) == 0.0) {
               t= s;            /* need true dimension for memory allocation */
               while (*t && !isspace(*t)) {
                 if (toupper(*t++) == 'B'
                  && k == qh_strtol(t, &t)
                  && *t++ == ':'
                  && qh_strtod(t, &t) == 0.0) {
                   qh->PROJECTinput++;
                   trace2((qh, qh->ferr, 2004, "qh_initflags: project dimension %d\n", k));
                   qh_option(qh, "Qb-project-dim", &k, NULL);
                   wasproject= True;
                   lastproject= k;
                   break;
                 }
               }
             }
           }
           if (!wasproject) {
             if (lastproject == k && r == 0.0)
               lastproject= -1;  /* doesn't catch all possible sequences */
             else if (key == 'b') {
               qh->SCALEinput= True;
               if (r == 0.0)
                 r= -qh_DEFAULTbox;
               qh_option(qh, "Qbound-dim-low", &k, &r);
             }else {
               qh->SCALEinput= True;
               if (r == 0.0)
                 r= qh_DEFAULTbox;
               qh_option(qh, "QBound-dim-high", &k, &r);
             }
           }
           break;
         case 'c':
           qh_option(qh, "Qcoplanar-keep", NULL, NULL);
           qh->KEEPcoplanar= True;
           break;
         case 'f':
           qh_option(qh, "Qfurthest-outside", NULL, NULL);
           qh->BESToutside= True;
           break;
         case 'g':
           qh_option(qh, "Qgood-facets-only", NULL, NULL);
           qh->ONLYgood= True;
           break;
         case 'i':
           qh_option(qh, "Qinterior-keep", NULL, NULL);
           qh->KEEPinside= True;
           break;
         case 'm':
           qh_option(qh, "Qmax-outside-only", NULL, NULL);
           qh->ONLYmax= True;
           break;
         case 'r':
           qh_option(qh, "Qrandom-outside", NULL, NULL);
           qh->RANDOMoutside= True;
           break;
         case 's':
           qh_option(qh, "Qsearch-initial-simplex", NULL, NULL);
           qh->ALLpoints= True;
           break;
         case 't':
           qh_option(qh, "Qtriangulate", NULL, NULL);
           qh->TRIangulate= True;
           break;
         case 'T':
           qh_option(qh, "QTestPoints", NULL, NULL);
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 6039, "qhull input error: missing number of test points for option 'QTn'\n");
           else {
             qh->TESTpoints= qh_strtol(s, &s);
             qh_option(qh, "QTestPoints", &qh->TESTpoints, NULL);
           }
           break;
         case 'u':
           qh_option(qh, "QupperDelaunay", NULL, NULL);
           qh->UPPERdelaunay= True;
           break;
         case 'v':
           qh_option(qh, "Qvertex-neighbors-convex", NULL, NULL);
           qh->TESTvneighbors= True;
           break;
         case 'x':
           qh_option(qh, "Qxact-merge", NULL, NULL);
           qh->MERGEexact= True;
           break;
         case 'z':
           qh_option(qh, "Qz-infinity-point", NULL, NULL);
           qh->ATinfinity= True;
           break;
         case '0':
           qh_option(qh, "Q0-no-premerge", NULL, NULL);
           qh->NOpremerge= True;
           break;
         case '1':
           if (!isdigit(*s)) {
             qh_option(qh, "Q1-no-angle-sort", NULL, NULL);
             qh->ANGLEmerge= False;
             break;
           }
           switch (*s++) {
           case '0':
             qh_option(qh, "Q10-no-narrow", NULL, NULL);
             qh->NOnarrow= True;
             break;
           case '1':
             qh_option(qh, "Q11-trinormals Qtriangulate", NULL, NULL);
             qh->TRInormals= True;
             qh->TRIangulate= True;
             break;
           default:
             s--;
             qh_fprintf(qh, qh->ferr, 7016, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);
             while (*++s && !isspace(*s));
             break;
           }
           break;
         case '2':
           qh_option(qh, "Q2-no-merge-independent", NULL, NULL);
           qh->MERGEindependent= False;
           goto LABELcheckdigit;
           break; /* no warnings */
         case '3':
           qh_option(qh, "Q3-no-merge-vertices", NULL, NULL);
           qh->MERGEvertices= False;
         LABELcheckdigit:
           if (isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7017, "qhull warning: can not follow '1', '2', or '3' with a digit.  '%c' skipped.\n",
                      *s++);
           break;
         case '4':
           qh_option(qh, "Q4-avoid-old-into-new", NULL, NULL);
           qh->AVOIDold= True;
           break;
         case '5':
           qh_option(qh, "Q5-no-check-outer", NULL, NULL);
           qh->SKIPcheckmax= True;
           break;
         case '6':
           qh_option(qh, "Q6-no-concave-merge", NULL, NULL);
           qh->SKIPconvex= True;
           break;
         case '7':
           qh_option(qh, "Q7-no-breadth-first", NULL, NULL);
           qh->VIRTUALmemory= True;
           break;
         case '8':
           qh_option(qh, "Q8-no-near-inside", NULL, NULL);
           qh->NOnearinside= True;
           break;
         case '9':
           qh_option(qh, "Q9-pick-furthest", NULL, NULL);
           qh->PICKfurthest= True;
           break;
         case 'G':
           i= qh_strtol(s, &t);
           if (qh->GOODpoint)
             qh_fprintf(qh, qh->ferr, 7018, "qhull warning: good point already defined for option 'QGn'.  Ignored\n");
           else if (s == t)
             qh_fprintf(qh, qh->ferr, 7019, "qhull warning: missing good point id for option 'QGn'.  Ignored\n");
           else if (i < 0 || *s == '-') {
             qh->GOODpoint= i-1;
             qh_option(qh, "QGood-if-dont-see-point", &i, NULL);
           }else {
             qh->GOODpoint= i+1;
             qh_option(qh, "QGood-if-see-point", &i, NULL);
           }
           s= t;
           break;
         case 'J':
           if (!isdigit(*s) && *s != '-')
             qh->JOGGLEmax= 0.0;
           else {
             qh->JOGGLEmax= (realT) qh_strtod(s, &s);
             qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
           }
           break;
         case 'R':
           if (!isdigit(*s) && *s != '-')
             qh_fprintf(qh, qh->ferr, 7020, "qhull warning: missing random seed for option 'QRn'.  Ignored\n");
           else {
             qh->ROTATErandom= i= qh_strtol(s, &s);
             if (i > 0)
               qh_option(qh, "QRotate-id", &i, NULL );
             else if (i < -1)
               qh_option(qh, "QRandom-seed", &i, NULL );
           }
           break;
         case 'V':
           i= qh_strtol(s, &t);
           if (qh->GOODvertex)
             qh_fprintf(qh, qh->ferr, 7021, "qhull warning: good vertex already defined for option 'QVn'.  Ignored\n");
           else if (s == t)
             qh_fprintf(qh, qh->ferr, 7022, "qhull warning: no good point id given for option 'QVn'.  Ignored\n");
           else if (i < 0) {
             qh->GOODvertex= i - 1;
             qh_option(qh, "QV-good-facets-not-point", &i, NULL);
           }else {
             qh_option(qh, "QV-good-facets-point", &i, NULL);
             qh->GOODvertex= i + 1;
           }
           s= t;
           break;
         default:
           s--;
           qh_fprintf(qh, qh->ferr, 7023, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     case 'T':
       while (*s && !isspace(*s)) {
         if (isdigit(*s) || *s == '-')
           qh->IStracing= qh_strtol(s, &s);
         else switch (*s++) {
         case 'a':
           qh_option(qh, "Tannotate-output", NULL, NULL);
           qh->ANNOTATEoutput= True;
           break;
         case 'c':
           qh_option(qh, "Tcheck-frequently", NULL, NULL);
           qh->CHECKfrequently= True;
           break;
         case 's':
           qh_option(qh, "Tstatistics", NULL, NULL);
           qh->PRINTstatistics= True;
           break;
         case 'v':
           qh_option(qh, "Tverify", NULL, NULL);
           qh->VERIFYoutput= True;
           break;
         case 'z':
           if (qh->ferr == qh_FILEstderr) {
             /* The C++ interface captures the output in qh_fprint_qhull() */
             qh_option(qh, "Tz-stdout", NULL, NULL);
             qh->USEstdout= True;
           }else if (!qh->fout)
             qh_fprintf(qh, qh->ferr, 7024, "qhull warning: output file undefined(stdout).  Option 'Tz' ignored.\n");
           else {
             qh_option(qh, "Tz-stdout", NULL, NULL);
             qh->USEstdout= True;
             qh->ferr= qh->fout;
             qh->qhmem.ferr= qh->fout;
           }
           break;
         case 'C':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7025, "qhull warning: missing point id for cone for trace option 'TCn'.  Ignored\n");
           else {
             i= qh_strtol(s, &s);
             qh_option(qh, "TCone-stop", &i, NULL);
             qh->STOPcone= i + 1;
           }
           break;
         case 'F':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7026, "qhull warning: missing frequency count for trace option 'TFn'.  Ignored\n");
           else {
             qh->REPORTfreq= qh_strtol(s, &s);
             qh_option(qh, "TFacet-log", &qh->REPORTfreq, NULL);
             qh->REPORTfreq2= qh->REPORTfreq/2;  /* for tracemerging() */
           }
           break;
         case 'I':
           if (!isspace(*s))
             qh_fprintf(qh, qh->ferr, 7027, "qhull warning: missing space between 'TI' and filename, %s\n", s);
           while (isspace(*s))
             s++;
           t= qh_skipfilename(qh, s);
           {
             char filename[qh_FILENAMElen];
 
             qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s));   /* WARN64 */
             s= t;
             if (!freopen(filename, "r", stdin)) {
               qh_fprintf(qh, qh->ferr, 6041, "qhull error: could not open file \"%s\".", filename);
               qh_errexit(qh, qh_ERRinput, NULL, NULL);
             }else {
               qh_option(qh, "TInput-file", NULL, NULL);
               qh_option(qh, filename, NULL, NULL);
             }
           }
           break;
         case 'O':
             if (!isspace(*s))
                 qh_fprintf(qh, qh->ferr, 7028, "qhull warning: missing space between 'TO' and filename, %s\n", s);
             while (isspace(*s))
                 s++;
             t= qh_skipfilename(qh, s);
             {
               char filename[qh_FILENAMElen];
 
               qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s));  /* WARN64 */
               s= t;
               if (!freopen(filename, "w", stdout)) {
                 qh_fprintf(qh, qh->ferr, 6044, "qhull error: could not open file \"%s\".", filename);
                 qh_errexit(qh, qh_ERRinput, NULL, NULL);
               }else {
                 qh_option(qh, "TOutput-file", NULL, NULL);
               qh_option(qh, filename, NULL, NULL);
             }
           }
           break;
         case 'P':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7029, "qhull warning: missing point id for trace option 'TPn'.  Ignored\n");
           else {
             qh->TRACEpoint= qh_strtol(s, &s);
             qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);
           }
           break;
         case 'M':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7030, "qhull warning: missing merge id for trace option 'TMn'.  Ignored\n");
           else {
             qh->TRACEmerge= qh_strtol(s, &s);
             qh_option(qh, "Trace-merge", &qh->TRACEmerge, NULL);
           }
           break;
         case 'R':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7031, "qhull warning: missing rerun count for trace option 'TRn'.  Ignored\n");
           else {
             qh->RERUN= qh_strtol(s, &s);
             qh_option(qh, "TRerun", &qh->RERUN, NULL);
           }
           break;
         case 'V':
           i= qh_strtol(s, &t);
           if (s == t)
             qh_fprintf(qh, qh->ferr, 7032, "qhull warning: missing furthest point id for trace option 'TVn'.  Ignored\n");
           else if (i < 0) {
             qh->STOPpoint= i - 1;
             qh_option(qh, "TV-stop-before-point", &i, NULL);
           }else {
             qh->STOPpoint= i + 1;
             qh_option(qh, "TV-stop-after-point", &i, NULL);
           }
           s= t;
           break;
         case 'W':
           if (!isdigit(*s))
             qh_fprintf(qh, qh->ferr, 7033, "qhull warning: missing max width for trace option 'TWn'.  Ignored\n");
           else {
             qh->TRACEdist= (realT) qh_strtod(s, &s);
             qh_option(qh, "TWide-trace", NULL, &qh->TRACEdist);
           }
           break;
         default:
           s--;
           qh_fprintf(qh, qh->ferr, 7034, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);
           while (*++s && !isspace(*s));
           break;
         }
       }
       break;
     default:
       qh_fprintf(qh, qh->ferr, 7035, "qhull warning: unknown flag %c(%x)\n", (int)s[-1],
                (int)s[-1]);
       break;
     }
     if (s-1 == prev_s && *s && !isspace(*s)) {
       qh_fprintf(qh, qh->ferr, 7036, "qhull warning: missing space after flag %c(%x); reserved for menu. Skipped.\n",
                (int)*prev_s, (int)*prev_s);
       while (*s && !isspace(*s))
         s++;
     }
   }
   if (qh->STOPcone && qh->JOGGLEmax < REALmax/2)
     qh_fprintf(qh, qh->ferr, 7078, "qhull warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");
   if (isgeom && !qh->FORCEoutput && qh->PRINTout[1])
     qh_fprintf(qh, qh->ferr, 7037, "qhull warning: additional output formats are not compatible with Geomview\n");
   /* set derived values in qh_initqhull_globals */
 } /* initflags */
 
 
 /*---------------------------------
 
   qh_initqhull_buffers(qh)
     initialize global memory buffers
 
   notes:
     must match qh_freebuffers()
 */
 void qh_initqhull_buffers(qhT *qh) {
   int k;
 
   qh->TEMPsize= (qh->qhmem.LASTsize - sizeof(setT))/SETelemsize;
   if (qh->TEMPsize <= 0 || qh->TEMPsize > qh->qhmem.LASTsize)
     qh->TEMPsize= 8;  /* e.g., if qh_NOmem */
   qh->other_points= qh_setnew(qh, qh->TEMPsize);
   qh->del_vertices= qh_setnew(qh, qh->TEMPsize);
   qh->coplanarfacetset= qh_setnew(qh, qh->TEMPsize);
   qh->NEARzero= (realT *)qh_memalloc(qh, qh->hull_dim * sizeof(realT));
   qh->lower_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));
   qh->upper_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));
   qh->lower_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));
   qh->upper_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));
   for (k=qh->input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_ouputflags */
     qh->lower_threshold[k]= -REALmax;
     qh->upper_threshold[k]= REALmax;
     qh->lower_bound[k]= -REALmax;
     qh->upper_bound[k]= REALmax;
   }
   qh->gm_matrix= (coordT *)qh_memalloc(qh, (qh->hull_dim+1) * qh->hull_dim * sizeof(coordT));
   qh->gm_row= (coordT **)qh_memalloc(qh, (qh->hull_dim+1) * sizeof(coordT *));
 } /* initqhull_buffers */
 
 /*---------------------------------
 
   qh_initqhull_globals(qh, points, numpoints, dim, ismalloc )
     initialize globals
     if ismalloc
       points were malloc'd and qhull should free at end
 
   returns:
     sets qh.first_point, num_points, input_dim, hull_dim and others
     seeds random number generator (seed=1 if tracing)
     modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
     adjust user flags as needed
     also checks DIM3 dependencies and constants
 
   notes:
     do not use qh_point() since an input transformation may move them elsewhere
 
   see:
     qh_initqhull_start() sets default values for non-zero globals
 
   design:
     initialize points array from input arguments
     test for qh.ZEROcentrum
       (i.e., use opposite vertex instead of cetrum for convexity testing)
     initialize qh.CENTERtype, qh.normal_size,
       qh.center_size, qh.TRACEpoint/level,
     initialize and test random numbers
     qh_initqhull_outputflags() -- adjust and test output flags
 */
 void qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {
   int seed, pointsneeded, extra= 0, i, randi, k;
   realT randr;
   realT factorial;
 
   time_t timedata;
 
   trace0((qh, qh->ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh->rbox_command,
       qh->qhull_command));
   qh->POINTSmalloc= ismalloc;
   qh->first_point= points;
   qh->num_points= numpoints;
   qh->hull_dim= qh->input_dim= dim;
   if (!qh->NOpremerge && !qh->MERGEexact && !qh->PREmerge && qh->JOGGLEmax > REALmax/2) {
     qh->MERGING= True;
     if (qh->hull_dim <= 4) {
       qh->PREmerge= True;
       qh_option(qh, "_pre-merge", NULL, NULL);
     }else {
       qh->MERGEexact= True;
       qh_option(qh, "Qxact_merge", NULL, NULL);
     }
   }else if (qh->MERGEexact)
     qh->MERGING= True;
   if (!qh->NOpremerge && qh->JOGGLEmax > REALmax/2) {
 #ifdef qh_NOmerge
     qh->JOGGLEmax= 0.0;
 #endif
   }
   if (qh->TRIangulate && qh->JOGGLEmax < REALmax/2 && qh->PRINTprecision)
     qh_fprintf(qh, qh->ferr, 7038, "qhull warning: joggle('QJ') always produces simplicial output.  Triangulated output('Qt') does nothing.\n");
   if (qh->JOGGLEmax < REALmax/2 && qh->DELAUNAY && !qh->SCALEinput && !qh->SCALElast) {
     qh->SCALElast= True;
     qh_option(qh, "Qbbound-last-qj", NULL, NULL);
   }
   if (qh->MERGING && !qh->POSTmerge && qh->premerge_cos > REALmax/2
   && qh->premerge_centrum == 0) {
     qh->ZEROcentrum= True;
     qh->ZEROall_ok= True;
     qh_option(qh, "_zero-centrum", NULL, NULL);
   }
   if (qh->JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh->PRINTprecision)
     qh_fprintf(qh, qh->ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user.h).\n",
           REALepsilon);
 #ifdef qh_NOmerge
   if (qh->MERGING) {
     qh_fprintf(qh, qh->ferr, 6045, "qhull input error: merging not installed(qh_NOmerge + 'Qx', 'Cn' or 'An')\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
 #endif
   if (qh->DELAUNAY && qh->KEEPcoplanar && !qh->KEEPinside) {
     qh->KEEPinside= True;
     qh_option(qh, "Qinterior-keep", NULL, NULL);
   }
   if (qh->DELAUNAY && qh->HALFspace) {
     qh_fprintf(qh, qh->ferr, 6046, "qhull input error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (!qh->DELAUNAY && (qh->UPPERdelaunay || qh->ATinfinity)) {
     qh_fprintf(qh, qh->ferr, 6047, "qhull input error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (qh->UPPERdelaunay && qh->ATinfinity) {
     qh_fprintf(qh, qh->ferr, 6048, "qhull input error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (qh->SCALElast && !qh->DELAUNAY && qh->PRINTprecision)
     qh_fprintf(qh, qh->ferr, 7040, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
   qh->DOcheckmax= (!qh->SKIPcheckmax && qh->MERGING );
   qh->KEEPnearinside= (qh->DOcheckmax && !(qh->KEEPinside && qh->KEEPcoplanar)
                           && !qh->NOnearinside);
   if (qh->MERGING)
     qh->CENTERtype= qh_AScentrum;
   else if (qh->VORONOI)
     qh->CENTERtype= qh_ASvoronoi;
   if (qh->TESTvneighbors && !qh->MERGING) {
     qh_fprintf(qh, qh->ferr, 6049, "qhull input error: test vertex neighbors('Qv') needs a merge option\n");
     qh_errexit(qh, qh_ERRinput, NULL ,NULL);
   }
   if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay)) {
     qh->hull_dim -= qh->PROJECTinput;
     if (qh->DELAUNAY) {
       qh->hull_dim++;
       if (qh->ATinfinity)
         extra= 1;
     }
   }
   if (qh->hull_dim <= 1) {
     qh_fprintf(qh, qh->ferr, 6050, "qhull error: dimension %d must be > 1\n", qh->hull_dim);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   for (k=2, factorial=1.0; k < qh->hull_dim; k++)
     factorial *= k;
   qh->AREAfactor= 1.0 / factorial;
   trace2((qh, qh->ferr, 2005, "qh_initqhull_globals: initialize globals.  dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n",
         dim, numpoints, ismalloc, qh->PROJECTinput, qh->hull_dim));
   qh->normal_size= qh->hull_dim * sizeof(coordT);
   qh->center_size= qh->normal_size - sizeof(coordT);
   pointsneeded= qh->hull_dim+1;
   if (qh->hull_dim > qh_DIMmergeVertex) {
     qh->MERGEvertices= False;
     qh_option(qh, "Q3-no-merge-vertices-dim-high", NULL, NULL);
   }
   if (qh->GOODpoint)
     pointsneeded++;
 #ifdef qh_NOtrace
   if (qh->IStracing) {
     qh_fprintf(qh, qh->ferr, 6051, "qhull input error: tracing is not installed(qh_NOtrace in user.h)");
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
 #endif
   if (qh->RERUN > 1) {
     qh->TRACElastrun= qh->IStracing; /* qh_build_withrestart duplicates next conditional */
     if (qh->IStracing != -1)
       qh->IStracing= 0;
   }else if (qh->TRACEpoint != -1 || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
     qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);
     qh->IStracing= 0;
   }
   if (qh->ROTATErandom == 0 || qh->ROTATErandom == -1) {
     seed= (int)time(&timedata);
     if (qh->ROTATErandom  == -1) {
       seed= -seed;
       qh_option(qh, "QRandom-seed", &seed, NULL );
     }else
       qh_option(qh, "QRotate-random", &seed, NULL);
     qh->ROTATErandom= seed;
   }
   seed= qh->ROTATErandom;
   if (seed == INT_MIN)    /* default value */
     seed= 1;
   else if (seed < 0)
     seed= -seed;
   qh_RANDOMseed_(qh, seed);
   randr= 0.0;
   for (i=1000; i--; ) {
     randi= qh_RANDOMint;
     randr += randi;
     if (randi > qh_RANDOMmax) {
       qh_fprintf(qh, qh->ferr, 8036, "\
 qhull configuration error (qh_RANDOMmax in user.h):\n\
    random integer %d > qh_RANDOMmax(qh, %.8g)\n",
                randi, qh_RANDOMmax);
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
   }
   qh_RANDOMseed_(qh, seed);
   randr = randr/1000;
   if (randr < qh_RANDOMmax * 0.1
   || randr > qh_RANDOMmax * 0.9)
     qh_fprintf(qh, qh->ferr, 8037, "\
 qhull configuration warning (qh_RANDOMmax in user.h):\n\
    average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\
    Is qh_RANDOMmax (%.2g) wrong?\n",
              randr, qh_RANDOMmax * 0.5, qh_RANDOMmax);
   qh->RANDOMa= 2.0 * qh->RANDOMfactor/qh_RANDOMmax;
   qh->RANDOMb= 1.0 - qh->RANDOMfactor;
   if (qh_HASHfactor < 1.1) {
     qh_fprintf(qh, qh->ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
       qh_HASHfactor);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   if (numpoints+extra < pointsneeded) {
     qh_fprintf(qh, qh->ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",
             numpoints, pointsneeded);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   qh_initqhull_outputflags(qh);
 } /* initqhull_globals */
 
 /*---------------------------------
 
   qh_initqhull_mem(qh, )
     initialize mem_r.c for qhull
     qh.hull_dim and qh.normal_size determine some of the allocation sizes
     if qh.MERGING,
       includes ridgeT
     calls qh_user_memsizes(qh) to add up to 10 additional sizes for quick allocation
       (see numsizes below)
 
   returns:
     mem_r.c already for qh_memalloc/qh_memfree (errors if called beforehand)
 
   notes:
     qh_produceoutput() prints memsizes
 
 */
 void qh_initqhull_mem(qhT *qh) {
   int numsizes;
   int i;
 
   numsizes= 8+10;
   qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, numsizes,
                      qh_MEMbufsize, qh_MEMinitbuf);
   qh_memsize(qh, (int)sizeof(vertexT));
   if (qh->MERGING) {
     qh_memsize(qh, (int)sizeof(ridgeT));
     qh_memsize(qh, (int)sizeof(mergeT));
   }
   qh_memsize(qh, (int)sizeof(facetT));
   i= sizeof(setT) + (qh->hull_dim - 1) * SETelemsize;  /* ridge.vertices */
   qh_memsize(qh, i);
   qh_memsize(qh, qh->normal_size);        /* normal */
   i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
   qh_memsize(qh, i);
   qh_user_memsizes(qh);
   qh_memsetup(qh);
 } /* initqhull_mem */
 
 /*---------------------------------
 
   qh_initqhull_outputflags
     initialize flags concerned with output
 
   returns:
     adjust user flags as needed
 
   see:
     qh_clear_outputflags() resets the flags
 
   design:
     test for qh.PRINTgood (i.e., only print 'good' facets)
     check for conflicting print output options
 */
 void qh_initqhull_outputflags(qhT *qh) {
   boolT printgeom= False, printmath= False, printcoplanar= False;
   int i;
 
   trace3((qh, qh->ferr, 3024, "qh_initqhull_outputflags: %s\n", qh->qhull_command));
   if (!(qh->PRINTgood || qh->PRINTneighbors)) {
     if (qh->KEEParea || qh->KEEPminArea < REALmax/2 || qh->KEEPmerge || qh->DELAUNAY
         || (!qh->ONLYgood && (qh->GOODvertex || qh->GOODpoint))) {
       qh->PRINTgood= True;
       qh_option(qh, "Pgood", NULL, NULL);
     }
   }
   if (qh->PRINTtransparent) {
     if (qh->hull_dim != 4 || !qh->DELAUNAY || qh->VORONOI || qh->DROPdim >= 0) {
       qh_fprintf(qh, qh->ferr, 6215, "qhull input error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     qh->DROPdim = 3;
     qh->PRINTridges = True;
   }
   for (i=qh_PRINTEND; i--; ) {
     if (qh->PRINTout[i] == qh_PRINTgeom)
       printgeom= True;
     else if (qh->PRINTout[i] == qh_PRINTmathematica || qh->PRINTout[i] == qh_PRINTmaple)
       printmath= True;
     else if (qh->PRINTout[i] == qh_PRINTcoplanars)
       printcoplanar= True;
     else if (qh->PRINTout[i] == qh_PRINTpointnearest)
       printcoplanar= True;
     else if (qh->PRINTout[i] == qh_PRINTpointintersect && !qh->HALFspace) {
       qh_fprintf(qh, qh->ferr, 6053, "qhull input error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }else if (qh->PRINTout[i] == qh_PRINTtriangles && (qh->HALFspace || qh->VORONOI)) {
       qh_fprintf(qh, qh->ferr, 6054, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }else if (qh->PRINTout[i] == qh_PRINTcentrums && qh->VORONOI) {
       qh_fprintf(qh, qh->ferr, 6055, "qhull input error: option 'FC' is not available for Voronoi vertices('v')\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }else if (qh->PRINTout[i] == qh_PRINTvertices) {
       if (qh->VORONOI)
         qh_option(qh, "Fvoronoi", NULL, NULL);
       else
         qh_option(qh, "Fvertices", NULL, NULL);
     }
   }
   if (printcoplanar && qh->DELAUNAY && qh->JOGGLEmax < REALmax/2) {
     if (qh->PRINTprecision)
       qh_fprintf(qh, qh->ferr, 7041, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
   }
   if (printmath && (qh->hull_dim > 3 || qh->VORONOI)) {
     qh_fprintf(qh, qh->ferr, 6056, "qhull input error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (printgeom) {
     if (qh->hull_dim > 4) {
       qh_fprintf(qh, qh->ferr, 6057, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     if (qh->PRINTnoplanes && !(qh->PRINTcoplanar + qh->PRINTcentrums
      + qh->PRINTdots + qh->PRINTspheres + qh->DOintersections + qh->PRINTridges)) {
       qh_fprintf(qh, qh->ferr, 6058, "qhull input error: no output specified for Geomview\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     if (qh->VORONOI && (qh->hull_dim > 3 || qh->DROPdim >= 0)) {
       qh_fprintf(qh, qh->ferr, 6059, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     /* can not warn about furthest-site Geomview output: no lower_threshold */
     if (qh->hull_dim == 4 && qh->DROPdim == -1 &&
         (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {
       qh_fprintf(qh, qh->ferr, 7042, "qhull input warning: coplanars, vertices, and centrums output not\n\
 available for 4-d output(ignored).  Could use 'GDn' instead.\n");
       qh->PRINTcoplanar= qh->PRINTspheres= qh->PRINTcentrums= False;
     }
   }
   if (!qh->KEEPcoplanar && !qh->KEEPinside && !qh->ONLYgood) {
     if ((qh->PRINTcoplanar && qh->PRINTspheres) || printcoplanar) {
       if (qh->QHULLfinished) {
         qh_fprintf(qh, qh->ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");
       }else {
         qh->KEEPcoplanar = True;
         qh_option(qh, "Qcoplanar", NULL, NULL);
       }
     }
   }
   qh->PRINTdim= qh->hull_dim;
   if (qh->DROPdim >=0) {    /* after Geomview checks */
     if (qh->DROPdim < qh->hull_dim) {
       qh->PRINTdim--;
       if (!printgeom || qh->hull_dim < 3)
         qh_fprintf(qh, qh->ferr, 7043, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh->DROPdim);
     }else
       qh->DROPdim= -1;
   }else if (qh->VORONOI) {
     qh->DROPdim= qh->hull_dim-1;
     qh->PRINTdim= qh->hull_dim-1;
   }
 } /* qh_initqhull_outputflags */
 
 /*---------------------------------
 
   qh_initqhull_start(qh, infile, outfile, errfile )
     allocate memory if needed and call qh_initqhull_start2()
 */
 void qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {
 
   qh_initstatistics(qh);
   qh_initqhull_start2(qh, infile, outfile, errfile);
 } /* initqhull_start */
 
 /*---------------------------------
 
   qh_initqhull_start2(qh, infile, outfile, errfile )
     start initialization of qhull
     initialize statistics, stdio, default values for global variables
     assumes qh is allocated
   notes:
     report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized
   see:
     qh_maxmin() determines the precision constants
     qh_freeqhull()
 */
 void qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {
   time_t timedata;
   int seed;
 
   qh_CPUclock; /* start the clock(for qh_clock).  One-shot. */
   /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */
   memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));   /* every field is 0, FALSE, NULL */
   qh->NOerrexit= True;
   qh->ANGLEmerge= True;
   qh->DROPdim= -1;
   qh->ferr= errfile;
   qh->fin= infile;
   qh->fout= outfile;
   qh->furthest_id= -1;
   qh->JOGGLEmax= REALmax;
   qh->KEEPminArea = REALmax;
   qh->last_low= REALmax;
   qh->last_high= REALmax;
   qh->last_newhigh= REALmax;
   qh->last_random= 1;
   qh->max_outside= 0.0;
   qh->max_vertex= 0.0;
   qh->MAXabs_coord= 0.0;
   qh->MAXsumcoord= 0.0;
   qh->MAXwidth= -REALmax;
   qh->MERGEindependent= True;
   qh->MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */
   qh->MINoutside= 0.0;
   qh->MINvisible= REALmax;
   qh->MAXcoplanar= REALmax;
   qh->outside_err= REALmax;
   qh->premerge_centrum= 0.0;
   qh->premerge_cos= REALmax;
   qh->PRINTprecision= True;
   qh->PRINTradius= 0.0;
   qh->postmerge_cos= REALmax;
   qh->postmerge_centrum= 0.0;
   qh->ROTATErandom= INT_MIN;
   qh->MERGEvertices= True;
   qh->totarea= 0.0;
   qh->totvol= 0.0;
   qh->TRACEdist= REALmax;
   qh->TRACEpoint= -1; /* recompile or use 'TPn' */
   qh->tracefacet_id= UINT_MAX;  /* recompile to trace a facet */
   qh->tracevertex_id= UINT_MAX; /* recompile to trace a vertex */
   seed= (int)time(&timedata);
   qh_RANDOMseed_(qh, seed);
   qh->run_id= qh_RANDOMint;
   if(!qh->run_id)
       qh->run_id++;  /* guarantee non-zero */
   qh_option(qh, "run-id", &qh->run_id, NULL);
   strcat(qh->qhull, "qhull");
 } /* initqhull_start2 */
 
 /*---------------------------------
 
   qh_initthresholds(qh, commandString )
     set thresholds for printing and scaling from commandString
 
   returns:
     sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used
 
   see:
     qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
     qh_inthresholds()
 
   design:
     for each 'Pdn' or 'PDn' option
       check syntax
       set qh.lower_threshold or qh.upper_threshold
     set qh.GOODthreshold if an unbounded threshold is used
     set qh.SPLITthreshold if a bounded threshold is used
 */
 void qh_initthresholds(qhT *qh, char *command) {
   realT value;
   int idx, maxdim, k;
   char *s= command; /* non-const due to strtol */
   char key;
 
   maxdim= qh->input_dim;
   if (qh->DELAUNAY && (qh->PROJECTdelaunay || qh->PROJECTinput))
     maxdim++;
   while (*s) {
     if (*s == '-')
       s++;
     if (*s == 'P') {
       s++;
       while (*s && !isspace(key= *s++)) {
         if (key == 'd' || key == 'D') {
           if (!isdigit(*s)) {
             qh_fprintf(qh, qh->ferr, 7044, "qhull warning: no dimension given for Print option '%c' at: %s.  Ignored\n",
                     key, s-1);
             continue;
           }
           idx= qh_strtol(s, &s);
           if (idx >= qh->hull_dim) {
             qh_fprintf(qh, qh->ferr, 7045, "qhull warning: dimension %d for Print option '%c' is >= %d.  Ignored\n",
                 idx, key, qh->hull_dim);
             continue;
           }
           if (*s == ':') {
             s++;
             value= qh_strtod(s, &s);
             if (fabs((double)value) > 1.0) {
               qh_fprintf(qh, qh->ferr, 7046, "qhull warning: value %2.4g for Print option %c is > +1 or < -1.  Ignored\n",
                       value, key);
               continue;
             }
           }else
             value= 0.0;
           if (key == 'd')
             qh->lower_threshold[idx]= value;
           else
             qh->upper_threshold[idx]= value;
         }
       }
     }else if (*s == 'Q') {
       s++;
       while (*s && !isspace(key= *s++)) {
         if (key == 'b' && *s == 'B') {
           s++;
           for (k=maxdim; k--; ) {
             qh->lower_bound[k]= -qh_DEFAULTbox;
             qh->upper_bound[k]= qh_DEFAULTbox;
           }
         }else if (key == 'b' && *s == 'b')
           s++;
         else if (key == 'b' || key == 'B') {
           if (!isdigit(*s)) {
             qh_fprintf(qh, qh->ferr, 7047, "qhull warning: no dimension given for Qhull option %c.  Ignored\n",
                     key);
             continue;
           }
           idx= qh_strtol(s, &s);
           if (idx >= maxdim) {
             qh_fprintf(qh, qh->ferr, 7048, "qhull warning: dimension %d for Qhull option %c is >= %d.  Ignored\n",
                 idx, key, maxdim);
             continue;
           }
           if (*s == ':') {
             s++;
             value= qh_strtod(s, &s);
           }else if (key == 'b')
             value= -qh_DEFAULTbox;
           else
             value= qh_DEFAULTbox;
           if (key == 'b')
             qh->lower_bound[idx]= value;
           else
             qh->upper_bound[idx]= value;
         }
       }
     }else {
       while (*s && !isspace(*s))
         s++;
     }
     while (isspace(*s))
       s++;
   }
   for (k=qh->hull_dim; k--; ) {
     if (qh->lower_threshold[k] > -REALmax/2) {
       qh->GOODthreshold= True;
       if (qh->upper_threshold[k] < REALmax/2) {
         qh->SPLITthresholds= True;
         qh->GOODthreshold= False;
         break;
       }
     }else if (qh->upper_threshold[k] < REALmax/2)
       qh->GOODthreshold= True;
   }
 } /* initthresholds */
 
 /*---------------------------------
 
   qh_option(qh, option, intVal, realVal )
     add an option description to qh.qhull_options
 
   notes:
     NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]
     will be printed with statistics ('Ts') and errors
     strlen(option) < 40
 */
 void qh_option(qhT *qh, const char *option, int *i, realT *r) {
   char buf[200];
   int len, maxlen;
 
   sprintf(buf, "  %s", option);
   if (i)
     sprintf(buf+strlen(buf), " %d", *i);
   if (r)
     sprintf(buf+strlen(buf), " %2.2g", *r);
   len= (int)strlen(buf);  /* WARN64 */
   qh->qhull_optionlen += len;
   maxlen= sizeof(qh->qhull_options) - len -1;
   maximize_(maxlen, 0);
   if (qh->qhull_optionlen >= qh_OPTIONline && maxlen > 0) {
     qh->qhull_optionlen= len;
     strncat(qh->qhull_options, "\n", (size_t)(maxlen--));
   }
   strncat(qh->qhull_options, buf, (size_t)maxlen);
 } /* option */
 
diff --git a/src/libqhullr/index.htm b/src/libqhullr/index.htm
index b9ca9d0..15f84b8 100644
--- a/src/libqhullr/index.htm
+++ b/src/libqhullr/index.htm
@@ -1,248 +1,248 @@
 
 
 
 
 Qhull functions, macros, and data structures
 
 
 
 
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


Qhull functions, macros, and data structures

The following sections provide an overview and index to Qhull's functions, macros, and data structures. Each section starts with an introduction. If you use Opera, the source code links back to this documentation. See also Calling Qhull from C programs and Calling Qhull from C++ programs.

Qhull uses the following conventions:

  • in code, global variables start with "qh "
  • in documentation, global variables start with 'qh.'
  • constants start with an upper case word
  • important globals include an '_'
  • functions, macros, and constants start with "qh_"
  • data types end in "T"
  • macros with arguments end in "_"
  • iterators are macros that use local variables
  • iterators for sets start with "FOREACH"
  • iterators for lists start with "FORALL"
  • qhull options are in single quotes (e.g., 'Pdn')
  • lists are sorted alphabetically
  • preprocessor directives on left margin for older compilers

When reading the code, please note that the global data structure, 'qh', is a macro. It either expands to "qh_qh." or to "qh_qh->". The later is used for applications which run concurrent calls to qh_qhull().

When reading code with an editor, a search for "procedure will locate the header of qh_procedure. A search for * procedure will locate the tail of qh_procedure.

A useful starting point is libqhull.h. It defines most of Qhull data structures and top-level functions. Search for 'PFn' to determine the corresponding constant in Qhull. Search for 'Fp' to determine the corresponding qh_PRINT... constant. Search io.c to learn how the print function is implemented.

If your web browser loads .c and .h files with an external application, change the MIME type of .c and .h files to "text/html". Opera does not always work since it treats '<' characters as HTML tags.

Please report documentation and link errors to qhull-bug@qhull.org.

-

Copyright © 1997-2012 C.B. Barber

+

Copyright © 1997-2015 C.B. Barber


»Qhull files

This sections lists the .c and .h files for Qhull. Please refer to these files for detailed information.

Makefile, CMakeLists.txt
Makefile is preconfigured for gcc. CMakeLists.txt supports multiple platforms with CMake. Qhull includes project files for Visual Studio and Qt.
 
libqhull.h
Include file for the Qhull library (libqhull.so, qhull.dll, libqhullstatic.a). Data structures are documented under Poly. Global variables are documented under Global. Other data structures and variables are documented under Qhull or Geom.
 
Geom, geom.h, geom.c, geom2.c, random.c, random.h
Geometric routines. These routines implement mathematical functions such as Gaussian elimination and geometric routines needed for Qhull. Frequently used routines are in geom.c while infrequent ones are in geom2.c.
 
Global, global.c, libqhull.h
Global routines. Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. global.c initializes and frees these structures.
 
Io, io.h, io.c
Input and output routines. Qhull provides a wide range of input and output options.
 
Mem, mem.h, mem.c
Memory routines. Qhull provides memory allocation and deallocation. It uses quick-fit allocation.
 
Merge, merge.h, merge.c
Merge routines. Qhull handles precision problems by merged facets or joggled input. These routines merge simplicial facets, merge non-simplicial facets, merge cycles of facets, and rename redundant vertices.
 
Poly, poly.h, poly.c, poly2.c, libqhull.h
Polyhedral routines. Qhull produces a polyhedron as a list of facets with vertices, neighbors, ridges, and geometric information. libqhull.h defines the main data structures. Frequently used routines are in poly.c while infrequent ones are in poly2.c.
 
Qhull, libqhull.c, libqhull.h, qhull_a.h, unix.c , qconvex.c , qdelaun.c , qhalf.c , qvoronoi.c
Top-level routines. The Quickhull algorithm is implemented by libqhull.c. qhull_a.h includes all header files.
 
Set, qset.h, qset.c
Set routines. Qhull implements its data structures as sets. A set is an array of pointers that is expanded as needed. This is a separate package that may be used in other applications.
 
Stat, stat.h, stat.c
Statistical routines. Qhull maintains statistics about its implementation.
 
User, user.h, user.c, user_eg.c, user_eg2.c, user_eg3.cpp, qhull_interface.cpp
User-defined routines. Qhull allows the user to configure the code with defined constants and specialized routines.


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull files
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/io_r.c b/src/libqhullr/io_r.c index b7c8380..53d1ca3 100644 --- a/src/libqhullr/io_r.c +++ b/src/libqhullr/io_r.c @@ -1,4062 +1,4062 @@ /*
  ---------------------------------
 
    io_r.c
    Input/Output routines of qhull application
 
    see qh-io.htm and io_r.h
 
    see user_r.c for qh_errprint and qh_printfacetlist
 
    unix_r.c calls qh_readpoints and qh_produce_output
 
    unix_r.c and user_r.c are the only callers of io_r.c functions
    This allows the user to avoid loading io_r.o from qhull.a
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/io_r.c#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/io_r.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_ra.h"
 
 /*========= -functions in alphabetical order after qh_produce_output(qh)  =====*/
 
 /*---------------------------------
 
   qh_produce_output(qh)
   qh_produce_output2(qh)
     prints out the result of qhull in desired format
     qh_produce_output2(qh) does not call qh_prepare_output(qh)
     if qh.GETarea
       computes and prints area and volume
     qh.PRINTout[] is an array of output formats
 
   notes:
     prints output in qh.PRINTout order
 */
 void qh_produce_output(qhT *qh) {
     int tempsize= qh_setsize(qh, qh->qhmem.tempstack);
 
     qh_prepare_output(qh);
     qh_produce_output2(qh);
     if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {
         qh_fprintf(qh, qh->ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",
             qh_setsize(qh, qh->qhmem.tempstack));
         qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }
 } /* produce_output */
 
 
 void qh_produce_output2(qhT *qh) {
   int i, tempsize= qh_setsize(qh, qh->qhmem.tempstack), d_1;
 
   if (qh->PRINTsummary)
     qh_printsummary(qh, qh->ferr);
   else if (qh->PRINTout[0] == qh_PRINTnone)
     qh_printsummary(qh, qh->fout);
   for (i=0; i < qh_PRINTEND; i++)
     qh_printfacets(qh, qh->fout, qh->PRINTout[i], qh->facet_list, NULL, !qh_ALL);
   qh_allstatistics(qh);
   if (qh->PRINTprecision && !qh->MERGING && (qh->JOGGLEmax > REALmax/2 || qh->RERUN))
     qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);
   if (qh->VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
     qh_printstats(qh, qh->ferr, qh->qhstat.vridges, NULL);
   if (qh->PRINTstatistics) {
     qh_printstatistics(qh, qh->ferr, "");
     qh_memstatistics(qh, qh->ferr);
     d_1= sizeof(setT) + (qh->hull_dim - 1) * SETelemsize;
     qh_fprintf(qh, qh->ferr, 8040, "\
     size in bytes: merge %d ridge %d vertex %d facet %d\n\
          normal %d ridge vertices %d facet vertices or neighbors %d\n",
             (int)sizeof(mergeT), (int)sizeof(ridgeT),
             (int)sizeof(vertexT), (int)sizeof(facetT),
             qh->normal_size, d_1, d_1 + SETelemsize);
   }
   if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {
     qh_fprintf(qh, qh->ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",
              qh_setsize(qh, qh->qhmem.tempstack));
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
 } /* produce_output2 */
 
 /*---------------------------------
 
   qh_dfacet(qh, id )
     print facet by id, for debugging
 
 */
 void qh_dfacet(qhT *qh, unsigned id) {
   facetT *facet;
 
   FORALLfacets {
     if (facet->id == id) {
       qh_printfacet(qh, qh->fout, facet);
       break;
     }
   }
 } /* qh_dfacet */
 
 
 /*---------------------------------
 
   qh_dvertex(qh, id )
     print vertex by id, for debugging
 */
 void qh_dvertex(qhT *qh, unsigned id) {
   vertexT *vertex;
 
   FORALLvertices {
     if (vertex->id == id) {
       qh_printvertex(qh, qh->fout, vertex);
       break;
     }
   }
 } /* qh_dvertex */
 
 
 /*---------------------------------
 
   qh_compare_facetarea(p1, p2 )
     used by qsort() to order facets by area
 */
 int qh_compare_facetarea(const void *p1, const void *p2) {
   const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
 
   if (!a->isarea)
     return -1;
   if (!b->isarea)
     return 1;
   if (a->f.area > b->f.area)
     return 1;
   else if (a->f.area == b->f.area)
     return 0;
   return -1;
 } /* compare_facetarea */
 
 /*---------------------------------
 
   qh_compare_facetmerge(p1, p2 )
     used by qsort() to order facets by number of merges
 */
 int qh_compare_facetmerge(const void *p1, const void *p2) {
   const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
 
   return(a->nummerge - b->nummerge);
 } /* compare_facetvisit */
 
 /*---------------------------------
 
   qh_compare_facetvisit(p1, p2 )
     used by qsort() to order facets by visit id or id
 */
 int qh_compare_facetvisit(const void *p1, const void *p2) {
   const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
   int i,j;
 
   if (!(i= a->visitid))
     i= 0 - a->id; /* do not convert to int, sign distinguishes id from visitid */
   if (!(j= b->visitid))
     j= 0 - b->id;
   return(i - j);
 } /* compare_facetvisit */
 
 /*---------------------------------
 
   qh_compare_vertexpoint( p1, p2 )
     used by qsort() to order vertices by point id
 
   Not usable in qhulllib_r since qh_pointid depends on qh
 
   int qh_compare_vertexpoint(const void *p1, const void *p2) {
   const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);
 
   return((qh_pointid(qh, a->point) > qh_pointid(qh, b->point)?1:-1));
 }*/
 
 /*---------------------------------
 
   qh_copyfilename(qh, dest, size, source, length )
     copy filename identified by qh_skipfilename()
 
   notes:
     see qh_skipfilename() for syntax
 */
 void qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length) {
   char c= *source;
 
   if (length > size + 1) {
       qh_fprintf(qh, qh->ferr, 6040, "qhull error: filename is more than %d characters, %s\n",  size-1, source);
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   strncpy(filename, source, length);
   filename[length]= '\0';
   if (c == '\'' || c == '"') {
     char *s= filename + 1;
     char *t= filename;
     while (*s) {
       if (*s == c) {
           if (s[-1] == '\\')
               t[-1]= c;
       }else
           *t++= *s;
       s++;
     }
     *t= '\0';
   }
 } /* copyfilename */
 
 /*---------------------------------
 
   qh_countfacets(qh, facetlist, facets, printall,
           numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
     count good facets for printing and set visitid
     if allfacets, ignores qh_skipfacet()
 
   notes:
     qh_printsummary and qh_countfacets must match counts
 
   returns:
     numfacets, numsimplicial, total neighbors, numridges, coplanars
     each facet with ->visitid indicating 1-relative position
       ->visitid==0 indicates not good
 
   notes
     numfacets >= numsimplicial
     if qh.NEWfacets,
       does not count visible facets (matches qh_printafacet)
 
   design:
     for all facets on facetlist and in facets set
       unless facet is skipped or visible (i.e., will be deleted)
         mark facet->visitid
         update counts
 */
 void qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,
     int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
   facetT *facet, **facetp;
   int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
 
   FORALLfacet_(facetlist) {
     if ((facet->visible && qh->NEWfacets)
     || (!printall && qh_skipfacet(qh, facet)))
       facet->visitid= 0;
     else {
       facet->visitid= ++numfacets;
       totneighbors += qh_setsize(qh, facet->neighbors);
       if (facet->simplicial) {
         numsimplicial++;
         if (facet->keepcentrum && facet->tricoplanar)
           numtricoplanars++;
       }else
         numridges += qh_setsize(qh, facet->ridges);
       if (facet->coplanarset)
         numcoplanars += qh_setsize(qh, facet->coplanarset);
     }
   }
 
   FOREACHfacet_(facets) {
     if ((facet->visible && qh->NEWfacets)
     || (!printall && qh_skipfacet(qh, facet)))
       facet->visitid= 0;
     else {
       facet->visitid= ++numfacets;
       totneighbors += qh_setsize(qh, facet->neighbors);
       if (facet->simplicial){
         numsimplicial++;
         if (facet->keepcentrum && facet->tricoplanar)
           numtricoplanars++;
       }else
         numridges += qh_setsize(qh, facet->ridges);
       if (facet->coplanarset)
         numcoplanars += qh_setsize(qh, facet->coplanarset);
     }
   }
   qh->visit_id += numfacets+1;
   *numfacetsp= numfacets;
   *numsimplicialp= numsimplicial;
   *totneighborsp= totneighbors;
   *numridgesp= numridges;
   *numcoplanarsp= numcoplanars;
   *numtricoplanarsp= numtricoplanars;
 } /* countfacets */
 
 /*---------------------------------
 
   qh_detvnorm(qh, vertex, vertexA, centers, offset )
     compute separating plane of the Voronoi diagram for a pair of input sites
     centers= set of facets (i.e., Voronoi vertices)
       facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
 
   assumes:
     qh_ASvoronoi and qh_vertexneighbors() already set
 
   returns:
     norm
       a pointer into qh.gm_matrix to qh.hull_dim-1 reals
       copy the data before reusing qh.gm_matrix
     offset
       if 'QVn'
         sign adjusted so that qh.GOODvertexp is inside
       else
         sign adjusted so that vertex is inside
 
     qh.gm_matrix= simplex of points from centers relative to first center
 
   notes:
     in io_r.c so that code for 'v Tv' can be removed by removing io_r.c
     returns pointer into qh.gm_matrix to avoid tracking of temporary memory
 
   design:
     determine midpoint of input sites
     build points as the set of Voronoi vertices
     select a simplex from points (if necessary)
       include midpoint if the Voronoi region is unbounded
     relocate the first vertex of the simplex to the origin
     compute the normalized hyperplane through the simplex
     orient the hyperplane toward 'QVn' or 'vertex'
     if 'Tv' or 'Ts'
       if bounded
         test that hyperplane is the perpendicular bisector of the input sites
       test that Voronoi vertices not in the simplex are still on the hyperplane
     free up temporary memory
 */
 pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
   facetT *facet, **facetp;
   int  i, k, pointid, pointidA, point_i, point_n;
   setT *simplex= NULL;
   pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
   coordT *coord, *gmcoord, *normalp;
   setT *points= qh_settemp(qh, qh->TEMPsize);
   boolT nearzero= False;
   boolT unbounded= False;
   int numcenters= 0;
   int dim= qh->hull_dim - 1;
   realT dist, offset, angle, zero= 0.0;
 
   midpoint= qh->gm_matrix + qh->hull_dim * qh->hull_dim;  /* last row */
   for (k=0; k < dim; k++)
     midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
   FOREACHfacet_(centers) {
     numcenters++;
     if (!facet->visitid)
       unbounded= True;
     else {
       if (!facet->center)
         facet->center= qh_facetcenter(qh, facet->vertices);
       qh_setappend(qh, &points, facet->center);
     }
   }
   if (numcenters > dim) {
     simplex= qh_settemp(qh, qh->TEMPsize);
     qh_setappend(qh, &simplex, vertex->point);
     if (unbounded)
       qh_setappend(qh, &simplex, midpoint);
     qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);
     qh_setdelnth(qh, simplex, 0);
   }else if (numcenters == dim) {
     if (unbounded)
       qh_setappend(qh, &points, midpoint);
     simplex= points;
   }else {
     qh_fprintf(qh, qh->ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   i= 0;
   gmcoord= qh->gm_matrix;
   point0= SETfirstt_(simplex, pointT);
   FOREACHpoint_(simplex) {
     if (qh->IStracing >= 4)
       qh_printmatrix(qh, qh->ferr, "qh_detvnorm: Voronoi vertex or midpoint",
                               &point, 1, dim);
     if (point != point0) {
       qh->gm_row[i++]= gmcoord;
       coord= point0;
       for (k=dim; k--; )
         *(gmcoord++)= *point++ - *coord++;
     }
   }
   qh->gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
   normal= gmcoord;
   qh_sethyperplane_gauss(qh, dim, qh->gm_row, point0, True,
                 normal, &offset, &nearzero);
   if (qh->GOODvertexp == vertexA->point)
     inpoint= vertexA->point;
   else
     inpoint= vertex->point;
   zinc_(Zdistio);
   dist= qh_distnorm(qh, dim, inpoint, normal, &offset);
   if (dist > 0) {
     offset= -offset;
     normalp= normal;
     for (k=dim; k--; ) {
       *normalp= -(*normalp);
       normalp++;
     }
   }
   if (qh->VERIFYoutput || qh->PRINTstatistics) {
     pointid= qh_pointid(qh, vertex->point);
     pointidA= qh_pointid(qh, vertexA->point);
     if (!unbounded) {
       zinc_(Zdiststat);
       dist= qh_distnorm(qh, dim, midpoint, normal, &offset);
       if (dist < 0)
         dist= -dist;
       zzinc_(Zridgemid);
       wwmax_(Wridgemidmax, dist);
       wwadd_(Wridgemid, dist);
       trace4((qh, qh->ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
                  pointid, pointidA, dist));
       for (k=0; k < dim; k++)
         midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
       qh_normalize(qh, midpoint, dim, False);
       angle= qh_distnorm(qh, dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
       if (angle < 0.0)
         angle= angle + 1.0;
       else
         angle= angle - 1.0;
       if (angle < 0.0)
         angle -= angle;
       trace4((qh, qh->ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
                  pointid, pointidA, angle, nearzero));
       if (nearzero) {
         zzinc_(Zridge0);
         wwmax_(Wridge0max, angle);
         wwadd_(Wridge0, angle);
       }else {
         zzinc_(Zridgeok)
         wwmax_(Wridgeokmax, angle);
         wwadd_(Wridgeok, angle);
       }
     }
     if (simplex != points) {
       FOREACHpoint_i_(qh, points) {
         if (!qh_setin(simplex, point)) {
           facet= SETelemt_(centers, point_i, facetT);
           zinc_(Zdiststat);
           dist= qh_distnorm(qh, dim, point, normal, &offset);
           if (dist < 0)
             dist= -dist;
           zzinc_(Zridge);
           wwmax_(Wridgemax, dist);
           wwadd_(Wridge, dist);
           trace4((qh, qh->ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
                              pointid, pointidA, facet->visitid, dist));
         }
       }
     }
   }
   *offsetp= offset;
   if (simplex != points)
     qh_settempfree(qh, &simplex);
   qh_settempfree(qh, &points);
   return normal;
 } /* detvnorm */
 
 /*---------------------------------
 
   qh_detvridge(qh, vertexA )
     determine Voronoi ridge from 'seen' neighbors of vertexA
     include one vertex-at-infinite if an !neighbor->visitid
 
   returns:
     temporary set of centers (facets, i.e., Voronoi vertices)
     sorted by center id
 */
 setT *qh_detvridge(qhT *qh, vertexT *vertex) {
   setT *centers= qh_settemp(qh, qh->TEMPsize);
   setT *tricenters= qh_settemp(qh, qh->TEMPsize);
   facetT *neighbor, **neighborp;
   boolT firstinf= True;
 
   FOREACHneighbor_(vertex) {
     if (neighbor->seen) {
       if (neighbor->visitid) {
         if (!neighbor->tricoplanar || qh_setunique(qh, &tricenters, neighbor->center))
           qh_setappend(qh, ¢ers, neighbor);
       }else if (firstinf) {
         firstinf= False;
         qh_setappend(qh, ¢ers, neighbor);
       }
     }
   }
   qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(qh, centers),
              sizeof(facetT *), qh_compare_facetvisit);
   qh_settempfree(qh, &tricenters);
   return centers;
 } /* detvridge */
 
 /*---------------------------------
 
   qh_detvridge3(qh, atvertex, vertex )
     determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
     include one vertex-at-infinite for !neighbor->visitid
     assumes all facet->seen2= True
 
   returns:
     temporary set of centers (facets, i.e., Voronoi vertices)
     listed in adjacency order (!oriented)
     all facet->seen2= True
 
   design:
     mark all neighbors of atvertex
     for each adjacent neighbor of both atvertex and vertex
       if neighbor selected
         add neighbor to set of Voronoi vertices
 */
 setT *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex) {
   setT *centers= qh_settemp(qh, qh->TEMPsize);
   setT *tricenters= qh_settemp(qh, qh->TEMPsize);
   facetT *neighbor, **neighborp, *facet= NULL;
   boolT firstinf= True;
 
   FOREACHneighbor_(atvertex)
     neighbor->seen2= False;
   FOREACHneighbor_(vertex) {
     if (!neighbor->seen2) {
       facet= neighbor;
       break;
     }
   }
   while (facet) {
     facet->seen2= True;
     if (neighbor->seen) {
       if (facet->visitid) {
         if (!facet->tricoplanar || qh_setunique(qh, &tricenters, facet->center))
           qh_setappend(qh, ¢ers, facet);
       }else if (firstinf) {
         firstinf= False;
         qh_setappend(qh, ¢ers, facet);
       }
     }
     FOREACHneighbor_(facet) {
       if (!neighbor->seen2) {
         if (qh_setin(vertex->neighbors, neighbor))
           break;
         else
           neighbor->seen2= True;
       }
     }
     facet= neighbor;
   }
   if (qh->CHECKfrequently) {
     FOREACHneighbor_(vertex) {
       if (!neighbor->seen2) {
           qh_fprintf(qh, qh->ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",
                  qh_pointid(qh, vertex->point), neighbor->id);
         qh_errexit(qh, qh_ERRqhull, neighbor, NULL);
       }
     }
   }
   FOREACHneighbor_(atvertex)
     neighbor->seen2= True;
   qh_settempfree(qh, &tricenters);
   return centers;
 } /* detvridge3 */
 
 /*---------------------------------
 
   qh_eachvoronoi(qh, fp, printvridge, vertex, visitall, innerouter, inorder )
     if visitall,
       visit all Voronoi ridges for vertex (i.e., an input site)
     else
       visit all unvisited Voronoi ridges for vertex
       all vertex->seen= False if unvisited
     assumes
       all facet->seen= False
       all facet->seen2= True (for qh_detvridge3)
       all facet->visitid == 0 if vertex_at_infinity
                          == index of Voronoi vertex
                          >= qh.num_facets if ignored
     innerouter:
       qh_RIDGEall--  both inner (bounded) and outer(unbounded) ridges
       qh_RIDGEinner- only inner
       qh_RIDGEouter- only outer
 
     if inorder
       orders vertices for 3-d Voronoi diagrams
 
   returns:
     number of visited ridges (does not include previously visited ridges)
 
     if printvridge,
       calls printvridge( fp, vertex, vertexA, centers)
         fp== any pointer (assumes FILE*)
         vertex,vertexA= pair of input sites that define a Voronoi ridge
         centers= set of facets (i.e., Voronoi vertices)
                  ->visitid == index or 0 if vertex_at_infinity
                  ordered for 3-d Voronoi diagram
   notes:
     uses qh.vertex_visit
 
   see:
     qh_eachvoronoi_all()
 
   design:
     mark selected neighbors of atvertex
     for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
       for each unvisited vertex
         if atvertex and vertex share more than d-1 neighbors
           bump totalcount
           if printvridge defined
             build the set of shared neighbors (i.e., Voronoi vertices)
             call printvridge
 */
 int qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
   boolT unbounded;
   int count;
   facetT *neighbor, **neighborp, *neighborA, **neighborAp;
   setT *centers;
   setT *tricenters= qh_settemp(qh, qh->TEMPsize);
 
   vertexT *vertex, **vertexp;
   boolT firstinf;
   unsigned int numfacets= (unsigned int)qh->num_facets;
   int totridges= 0;
 
   qh->vertex_visit++;
   atvertex->seen= True;
   if (visitall) {
     FORALLvertices
       vertex->seen= False;
   }
   FOREACHneighbor_(atvertex) {
     if (neighbor->visitid < numfacets)
       neighbor->seen= True;
   }
   FOREACHneighbor_(atvertex) {
     if (neighbor->seen) {
       FOREACHvertex_(neighbor->vertices) {
         if (vertex->visitid != qh->vertex_visit && !vertex->seen) {
           vertex->visitid= qh->vertex_visit;
           count= 0;
           firstinf= True;
           qh_settruncate(qh, tricenters, 0);
           FOREACHneighborA_(vertex) {
             if (neighborA->seen) {
               if (neighborA->visitid) {
                 if (!neighborA->tricoplanar || qh_setunique(qh, &tricenters, neighborA->center))
                   count++;
               }else if (firstinf) {
                 count++;
                 firstinf= False;
               }
             }
           }
           if (count >= qh->hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
             if (firstinf) {
               if (innerouter == qh_RIDGEouter)
                 continue;
               unbounded= False;
             }else {
               if (innerouter == qh_RIDGEinner)
                 continue;
               unbounded= True;
             }
             totridges++;
             trace4((qh, qh->ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
                   count, qh_pointid(qh, atvertex->point), qh_pointid(qh, vertex->point)));
             if (printvridge && fp) {
               if (inorder && qh->hull_dim == 3+1) /* 3-d Voronoi diagram */
                 centers= qh_detvridge3(qh, atvertex, vertex);
               else
                 centers= qh_detvridge(qh, vertex);
               (*printvridge)(qh, fp, atvertex, vertex, centers, unbounded);
               qh_settempfree(qh, ¢ers);
             }
           }
         }
       }
     }
   }
   FOREACHneighbor_(atvertex)
     neighbor->seen= False;
   qh_settempfree(qh, &tricenters);
   return totridges;
 } /* eachvoronoi */
 
 
 /*---------------------------------
 
   qh_eachvoronoi_all(qh, fp, printvridge, isUpper, innerouter, inorder )
     visit all Voronoi ridges
 
     innerouter:
       see qh_eachvoronoi()
 
     if inorder
       orders vertices for 3-d Voronoi diagrams
 
   returns
     total number of ridges
 
     if isUpper == facet->upperdelaunay  (i.e., a Vornoi vertex)
       facet->visitid= Voronoi vertex index(same as 'o' format)
     else
       facet->visitid= 0
 
     if printvridge,
       calls printvridge( fp, vertex, vertexA, centers)
       [see qh_eachvoronoi]
 
   notes:
     Not used for qhull.exe
     same effect as qh_printvdiagram but ridges not sorted by point id
 */
 int qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {
   facetT *facet;
   vertexT *vertex;
   int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
   int totridges= 0;
 
   qh_clearcenters(qh, qh_ASvoronoi);
   qh_vertexneighbors(qh);
   maximize_(qh->visit_id, (unsigned) qh->num_facets);
   FORALLfacets {
     facet->visitid= 0;
     facet->seen= False;
     facet->seen2= True;
   }
   FORALLfacets {
     if (facet->upperdelaunay == isUpper)
       facet->visitid= numcenters++;
   }
   FORALLvertices
     vertex->seen= False;
   FORALLvertices {
     if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)
       continue;
     totridges += qh_eachvoronoi(qh, fp, printvridge, vertex,
                    !qh_ALL, innerouter, inorder);
   }
   return totridges;
 } /* eachvoronoi_all */
 
 /*---------------------------------
 
   qh_facet2point(qh, facet, point0, point1, mindist )
     return two projected temporary vertices for a 2-d facet
     may be non-simplicial
 
   returns:
     point0 and point1 oriented and projected to the facet
     returns mindist (maximum distance below plane)
 */
 void qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
   vertexT *vertex0, *vertex1;
   realT dist;
 
   if (facet->toporient ^ qh_ORIENTclock) {
     vertex0= SETfirstt_(facet->vertices, vertexT);
     vertex1= SETsecondt_(facet->vertices, vertexT);
   }else {
     vertex1= SETfirstt_(facet->vertices, vertexT);
     vertex0= SETsecondt_(facet->vertices, vertexT);
   }
   zadd_(Zdistio, 2);
   qh_distplane(qh, vertex0->point, facet, &dist);
   *mindist= dist;
   *point0= qh_projectpoint(qh, vertex0->point, facet, dist);
   qh_distplane(qh, vertex1->point, facet, &dist);
   minimize_(*mindist, dist);
   *point1= qh_projectpoint(qh, vertex1->point, facet, dist);
 } /* facet2point */
 
 
 /*---------------------------------
 
   qh_facetvertices(qh, facetlist, facets, allfacets )
     returns temporary set of vertices in a set and/or list of facets
     if allfacets, ignores qh_skipfacet()
 
   returns:
     vertices with qh.vertex_visit
 
   notes:
     optimized for allfacets of facet_list
 
   design:
     if allfacets of facet_list
       create vertex set from vertex_list
     else
       for each selected facet in facets or facetlist
         append unvisited vertices to vertex set
 */
 setT *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets) {
   setT *vertices;
   facetT *facet, **facetp;
   vertexT *vertex, **vertexp;
 
   qh->vertex_visit++;
   if (facetlist == qh->facet_list && allfacets && !facets) {
     vertices= qh_settemp(qh, qh->num_vertices);
     FORALLvertices {
       vertex->visitid= qh->vertex_visit;
       qh_setappend(qh, &vertices, vertex);
     }
   }else {
     vertices= qh_settemp(qh, qh->TEMPsize);
     FORALLfacet_(facetlist) {
       if (!allfacets && qh_skipfacet(qh, facet))
         continue;
       FOREACHvertex_(facet->vertices) {
         if (vertex->visitid != qh->vertex_visit) {
           vertex->visitid= qh->vertex_visit;
           qh_setappend(qh, &vertices, vertex);
         }
       }
     }
   }
   FOREACHfacet_(facets) {
     if (!allfacets && qh_skipfacet(qh, facet))
       continue;
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh->vertex_visit) {
         vertex->visitid= qh->vertex_visit;
         qh_setappend(qh, &vertices, vertex);
       }
     }
   }
   return vertices;
 } /* facetvertices */
 
 /*---------------------------------
 
   qh_geomplanes(qh, facet, outerplane, innerplane )
     return outer and inner planes for Geomview
     qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
 
   notes:
     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
 */
 void qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {
   realT radius;
 
   if (qh->MERGING || qh->JOGGLEmax < REALmax/2) {
     qh_outerinner(qh, facet, outerplane, innerplane);
     radius= qh->PRINTradius;
     if (qh->JOGGLEmax < REALmax/2)
       radius -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);  /* already accounted for in qh_outerinner() */
     *outerplane += radius;
     *innerplane -= radius;
     if (qh->PRINTcoplanar || qh->PRINTspheres) {
       *outerplane += qh->MAXabs_coord * qh_GEOMepsilon;
       *innerplane -= qh->MAXabs_coord * qh_GEOMepsilon;
     }
   }else
     *innerplane= *outerplane= 0;
 } /* geomplanes */
 
 
 /*---------------------------------
 
   qh_markkeep(qh, facetlist )
     mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
     ignores visible facets (!part of convex hull)
 
   returns:
     may clear facet->good
     recomputes qh.num_good
 
   design:
     get set of good facets
     if qh.KEEParea
       sort facets by area
       clear facet->good for all but n largest facets
     if qh.KEEPmerge
       sort facets by merge count
       clear facet->good for all but n most merged facets
     if qh.KEEPminarea
       clear facet->good if area too small
     update qh.num_good
 */
 void qh_markkeep(qhT *qh, facetT *facetlist) {
   facetT *facet, **facetp;
   setT *facets= qh_settemp(qh, qh->num_facets);
   int size, count;
 
   trace2((qh, qh->ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
           qh->KEEParea, qh->KEEPmerge, qh->KEEPminArea));
   FORALLfacet_(facetlist) {
     if (!facet->visible && facet->good)
       qh_setappend(qh, &facets, facet);
   }
   size= qh_setsize(qh, facets);
   if (qh->KEEParea) {
     qsort(SETaddr_(facets, facetT), (size_t)size,
              sizeof(facetT *), qh_compare_facetarea);
     if ((count= size - qh->KEEParea) > 0) {
       FOREACHfacet_(facets) {
         facet->good= False;
         if (--count == 0)
           break;
       }
     }
   }
   if (qh->KEEPmerge) {
     qsort(SETaddr_(facets, facetT), (size_t)size,
              sizeof(facetT *), qh_compare_facetmerge);
     if ((count= size - qh->KEEPmerge) > 0) {
       FOREACHfacet_(facets) {
         facet->good= False;
         if (--count == 0)
           break;
       }
     }
   }
   if (qh->KEEPminArea < REALmax/2) {
     FOREACHfacet_(facets) {
       if (!facet->isarea || facet->f.area < qh->KEEPminArea)
         facet->good= False;
     }
   }
   qh_settempfree(qh, &facets);
   count= 0;
   FORALLfacet_(facetlist) {
     if (facet->good)
       count++;
   }
   qh->num_good= count;
 } /* markkeep */
 
 
 /*---------------------------------
 
   qh_markvoronoi(qh, facetlist, facets, printall, isLower, numcenters )
     mark voronoi vertices for printing by site pairs
 
   returns:
     temporary set of vertices indexed by pointid
     isLower set if printing lower hull (i.e., at least one facet is lower hull)
     numcenters= total number of Voronoi vertices
     bumps qh.printoutnum for vertex-at-infinity
     clears all facet->seen and sets facet->seen2
 
     if selected
       facet->visitid= Voronoi vertex id
     else if upper hull (or 'Qu' and lower hull)
       facet->visitid= 0
     else
       facet->visitid >= qh->num_facets
 
   notes:
     ignores qh.ATinfinity, if defined
 */
 setT *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {
   int numcenters=0;
   facetT *facet, **facetp;
   setT *vertices;
   boolT isLower= False;
 
   qh->printoutnum++;
   qh_clearcenters(qh, qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
   qh_vertexneighbors(qh);
   vertices= qh_pointvertex(qh);
   if (qh->ATinfinity)
     SETelem_(vertices, qh->num_points-1)= NULL;
   qh->visit_id++;
   maximize_(qh->visit_id, (unsigned) qh->num_facets);
   FORALLfacet_(facetlist) {
     if (printall || !qh_skipfacet(qh, facet)) {
       if (!facet->upperdelaunay) {
         isLower= True;
         break;
       }
     }
   }
   FOREACHfacet_(facets) {
     if (printall || !qh_skipfacet(qh, facet)) {
       if (!facet->upperdelaunay) {
         isLower= True;
         break;
       }
     }
   }
   FORALLfacets {
     if (facet->normal && (facet->upperdelaunay == isLower))
       facet->visitid= 0;  /* facetlist or facets may overwrite */
     else
       facet->visitid= qh->visit_id;
     facet->seen= False;
     facet->seen2= True;
   }
   numcenters++;  /* qh_INFINITE */
   FORALLfacet_(facetlist) {
     if (printall || !qh_skipfacet(qh, facet))
       facet->visitid= numcenters++;
   }
   FOREACHfacet_(facets) {
     if (printall || !qh_skipfacet(qh, facet))
       facet->visitid= numcenters++;
   }
   *isLowerp= isLower;
   *numcentersp= numcenters;
   trace2((qh, qh->ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));
   return vertices;
 } /* markvoronoi */
 
 /*---------------------------------
 
   qh_order_vertexneighbors(qh, vertex )
     order facet neighbors of a 2-d or 3-d vertex by adjacency
 
   notes:
     does not orient the neighbors
 
   design:
     initialize a new neighbor set with the first facet in vertex->neighbors
     while vertex->neighbors non-empty
       select next neighbor in the previous facet's neighbor set
     set vertex->neighbors to the new neighbor set
 */
 void qh_order_vertexneighbors(qhT *qh, vertexT *vertex) {
   setT *newset;
   facetT *facet, *neighbor, **neighborp;
 
   trace4((qh, qh->ferr, 4018, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
   newset= qh_settemp(qh, qh_setsize(qh, vertex->neighbors));
   facet= (facetT*)qh_setdellast(vertex->neighbors);
   qh_setappend(qh, &newset, facet);
   while (qh_setsize(qh, vertex->neighbors)) {
     FOREACHneighbor_(vertex) {
       if (qh_setin(facet->neighbors, neighbor)) {
         qh_setdel(vertex->neighbors, neighbor);
         qh_setappend(qh, &newset, neighbor);
         facet= neighbor;
         break;
       }
     }
     if (!neighbor) {
       qh_fprintf(qh, qh->ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
         vertex->id, facet->id);
       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     }
   }
   qh_setfree(qh, &vertex->neighbors);
   qh_settemppop(qh);
   vertex->neighbors= newset;
 } /* order_vertexneighbors */
 
 /*---------------------------------
 
   qh_prepare_output(qh, )
     prepare for qh_produce_output2(qh) according to
       qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds
     does not reset facet->good
 
   notes
     except for PRINTstatistics, no-op if previously called with same options
 */
 void qh_prepare_output(qhT *qh) {
   if (qh->VORONOI) {
     qh_clearcenters(qh, qh_ASvoronoi);
     qh_vertexneighbors(qh);
   }
   if (qh->TRIangulate && !qh->hasTriangulation) {
     qh_triangulate(qh);
     if (qh->VERIFYoutput && !qh->CHECKfrequently)
       qh_checkpolygon(qh, qh->facet_list);
   }
   qh_findgood_all(qh, qh->facet_list);
   if (qh->GETarea)
     qh_getarea(qh, qh->facet_list);
   if (qh->KEEParea || qh->KEEPmerge || qh->KEEPminArea < REALmax/2)
     qh_markkeep(qh, qh->facet_list);
   if (qh->PRINTstatistics)
     qh_collectstatistics(qh);
 }
 
 /*---------------------------------
 
   qh_printafacet(qh, fp, format, facet, printall )
     print facet to fp in given output format (see qh.PRINTout)
 
   returns:
     nop if !printall and qh_skipfacet()
     nop if visible facet and NEWfacets and format != PRINTfacets
     must match qh_countfacets
 
   notes
     preserves qh.visit_id
     facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
 
   see
     qh_printbegin() and qh_printend()
 
   design:
     test for printing facet
     call appropriate routine for format
     or output results directly
 */
 void qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {
   realT color[4], offset, dist, outerplane, innerplane;
   boolT zerodiv;
   coordT *point, *normp, *coordp, **pointp, *feasiblep;
   int k;
   vertexT *vertex, **vertexp;
   facetT *neighbor, **neighborp;
 
   if (!printall && qh_skipfacet(qh, facet))
     return;
   if (facet->visible && qh->NEWfacets && format != qh_PRINTfacets)
     return;
   qh->printoutnum++;
   switch (format) {
   case qh_PRINTarea:
     if (facet->isarea) {
       qh_fprintf(qh, fp, 9009, qh_REAL_1, facet->f.area);
       qh_fprintf(qh, fp, 9010, "\n");
     }else
       qh_fprintf(qh, fp, 9011, "0\n");
     break;
   case qh_PRINTcoplanars:
     qh_fprintf(qh, fp, 9012, "%d", qh_setsize(qh, facet->coplanarset));
     FOREACHpoint_(facet->coplanarset)
       qh_fprintf(qh, fp, 9013, " %d", qh_pointid(qh, point));
     qh_fprintf(qh, fp, 9014, "\n");
     break;
   case qh_PRINTcentrums:
     qh_printcenter(qh, fp, format, NULL, facet);
     break;
   case qh_PRINTfacets:
     qh_printfacet(qh, fp, facet);
     break;
   case qh_PRINTfacets_xridge:
     qh_printfacetheader(qh, fp, facet);
     break;
   case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
     if (!facet->normal)
       break;
     for (k=qh->hull_dim; k--; ) {
       color[k]= (facet->normal[k]+1.0)/2.0;
       maximize_(color[k], -1.0);
       minimize_(color[k], +1.0);
     }
     qh_projectdim3(qh, color, color);
     if (qh->PRINTdim != qh->hull_dim)
       qh_normalize2(qh, color, 3, True, NULL, NULL);
     if (qh->hull_dim <= 2)
       qh_printfacet2geom(qh, fp, facet, color);
     else if (qh->hull_dim == 3) {
       if (facet->simplicial)
         qh_printfacet3geom_simplicial(qh, fp, facet, color);
       else
         qh_printfacet3geom_nonsimplicial(qh, fp, facet, color);
     }else {
       if (facet->simplicial)
         qh_printfacet4geom_simplicial(qh, fp, facet, color);
       else
         qh_printfacet4geom_nonsimplicial(qh, fp, facet, color);
     }
     break;
   case qh_PRINTids:
     qh_fprintf(qh, fp, 9015, "%d\n", facet->id);
     break;
   case qh_PRINTincidences:
   case qh_PRINToff:
   case qh_PRINTtriangles:
     if (qh->hull_dim == 3 && format != qh_PRINTtriangles)
       qh_printfacet3vertex(qh, fp, facet, format);
     else if (facet->simplicial || qh->hull_dim == 2 || format == qh_PRINToff)
       qh_printfacetNvertex_simplicial(qh, fp, facet, format);
     else
       qh_printfacetNvertex_nonsimplicial(qh, fp, facet, qh->printoutvar++, format);
     break;
   case qh_PRINTinner:
     qh_outerinner(qh, facet, NULL, &innerplane);
     offset= facet->offset - innerplane;
     goto LABELprintnorm;
     break; /* prevent warning */
   case qh_PRINTmerges:
     qh_fprintf(qh, fp, 9016, "%d\n", facet->nummerge);
     break;
   case qh_PRINTnormals:
     offset= facet->offset;
     goto LABELprintnorm;
     break; /* prevent warning */
   case qh_PRINTouter:
     qh_outerinner(qh, facet, &outerplane, NULL);
     offset= facet->offset - outerplane;
   LABELprintnorm:
     if (!facet->normal) {
       qh_fprintf(qh, fp, 9017, "no normal for facet f%d\n", facet->id);
       break;
     }
     if (qh->CDDoutput) {
       qh_fprintf(qh, fp, 9018, qh_REAL_1, -offset);
       for (k=0; k < qh->hull_dim; k++)
         qh_fprintf(qh, fp, 9019, qh_REAL_1, -facet->normal[k]);
     }else {
       for (k=0; k < qh->hull_dim; k++)
         qh_fprintf(qh, fp, 9020, qh_REAL_1, facet->normal[k]);
       qh_fprintf(qh, fp, 9021, qh_REAL_1, offset);
     }
     qh_fprintf(qh, fp, 9022, "\n");
     break;
   case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
   case qh_PRINTmaple:
     if (qh->hull_dim == 2)
       qh_printfacet2math(qh, fp, facet, format, qh->printoutvar++);
     else
       qh_printfacet3math(qh, fp, facet, format, qh->printoutvar++);
     break;
   case qh_PRINTneighbors:
     qh_fprintf(qh, fp, 9023, "%d", qh_setsize(qh, facet->neighbors));
     FOREACHneighbor_(facet)
       qh_fprintf(qh, fp, 9024, " %d",
                neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);
     qh_fprintf(qh, fp, 9025, "\n");
     break;
   case qh_PRINTpointintersect:
     if (!qh->feasible_point) {
       qh_fprintf(qh, qh->ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh->feasible_point\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     if (facet->offset > 0)
       goto LABELprintinfinite;
     point= coordp= (coordT*)qh_memalloc(qh, qh->normal_size);
     normp= facet->normal;
     feasiblep= qh->feasible_point;
     if (facet->offset < -qh->MINdenom) {
       for (k=qh->hull_dim; k--; )
         *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
     }else {
       for (k=qh->hull_dim; k--; ) {
         *(coordp++)= qh_divzero(qh, *(normp++), facet->offset, qh->MINdenom_1,
                                  &zerodiv) + *(feasiblep++);
         if (zerodiv) {
           qh_memfree(qh, point, qh->normal_size);
           goto LABELprintinfinite;
         }
       }
     }
     qh_printpoint(qh, fp, NULL, point);
     qh_memfree(qh, point, qh->normal_size);
     break;
   LABELprintinfinite:
     for (k=qh->hull_dim; k--; )
       qh_fprintf(qh, fp, 9026, qh_REAL_1, qh_INFINITE);
     qh_fprintf(qh, fp, 9027, "\n");
     break;
   case qh_PRINTpointnearest:
     FOREACHpoint_(facet->coplanarset) {
       int id, id2;
       vertex= qh_nearvertex(qh, facet, point, &dist);
       id= qh_pointid(qh, vertex->point);
       id2= qh_pointid(qh, point);
       qh_fprintf(qh, fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
     }
     break;
   case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
     if (qh->CDDoutput)
       qh_fprintf(qh, fp, 9029, "1 ");
     qh_printcenter(qh, fp, format, NULL, facet);
     break;
   case qh_PRINTvertices:
     qh_fprintf(qh, fp, 9030, "%d", qh_setsize(qh, facet->vertices));
     FOREACHvertex_(facet->vertices)
       qh_fprintf(qh, fp, 9031, " %d", qh_pointid(qh, vertex->point));
     qh_fprintf(qh, fp, 9032, "\n");
     break;
   default:
     break;
   }
 } /* printafacet */
 
 /*---------------------------------
 
   qh_printbegin(qh, )
     prints header for all output formats
 
   returns:
     checks for valid format
 
   notes:
     uses qh.visit_id for 3/4off
     changes qh.interior_point if printing centrums
     qh_countfacets clears facet->visitid for non-good facets
 
   see
     qh_printend() and qh_printafacet()
 
   design:
     count facets and related statistics
     print header for format
 */
 void qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
   int i, num;
   facetT *facet, **facetp;
   vertexT *vertex, **vertexp;
   setT *vertices;
   pointT *point, **pointp, *pointtemp;
 
   qh->printoutnum= 0;
   qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
   switch (format) {
   case qh_PRINTnone:
     break;
   case qh_PRINTarea:
     qh_fprintf(qh, fp, 9033, "%d\n", numfacets);
     break;
   case qh_PRINTcoplanars:
     qh_fprintf(qh, fp, 9034, "%d\n", numfacets);
     break;
   case qh_PRINTcentrums:
     if (qh->CENTERtype == qh_ASnone)
       qh_clearcenters(qh, qh_AScentrum);
     qh_fprintf(qh, fp, 9035, "%d\n%d\n", qh->hull_dim, numfacets);
     break;
   case qh_PRINTfacets:
   case qh_PRINTfacets_xridge:
     if (facetlist)
       qh_printvertexlist(qh, fp, "Vertices and facets:\n", facetlist, facets, printall);
     break;
   case qh_PRINTgeom:
     if (qh->hull_dim > 4)  /* qh_initqhull_globals also checks */
       goto LABELnoformat;
     if (qh->VORONOI && qh->hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
       goto LABELnoformat;
     if (qh->hull_dim == 2 && (qh->PRINTridges || qh->DOintersections))
       qh_fprintf(qh, qh->ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
     if (qh->hull_dim == 4 && (qh->PRINTinner || qh->PRINTouter ||
                              (qh->PRINTdim == 4 && qh->PRINTcentrums)))
       qh_fprintf(qh, qh->ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
     if (qh->PRINTdim == 4 && (qh->PRINTspheres))
       qh_fprintf(qh, qh->ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");
     if (qh->PRINTdim == 4 && qh->DOintersections && qh->PRINTnoplanes)
       qh_fprintf(qh, qh->ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");
     if (qh->PRINTdim == 2) {
       qh_fprintf(qh, fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",
               qh->rbox_command, qh->qhull_command);
     }else if (qh->PRINTdim == 3) {
       qh_fprintf(qh, fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
               qh->rbox_command, qh->qhull_command);
     }else if (qh->PRINTdim == 4) {
       qh->visit_id++;
       num= 0;
       FORALLfacet_(facetlist)    /* get number of ridges to be printed */
         qh_printend4geom(qh, NULL, facet, &num, printall);
       FOREACHfacet_(facets)
         qh_printend4geom(qh, NULL, facet, &num, printall);
       qh->ridgeoutnum= num;
       qh->printoutvar= 0;  /* counts number of ridges in output */
       qh_fprintf(qh, fp, 9038, "LIST # %s | %s\n", qh->rbox_command, qh->qhull_command);
     }
 
     if (qh->PRINTdots) {
       qh->printoutnum++;
       num= qh->num_points + qh_setsize(qh, qh->other_points);
       if (qh->DELAUNAY && qh->ATinfinity)
         num--;
       if (qh->PRINTdim == 4)
         qh_fprintf(qh, fp, 9039, "4VECT %d %d 1\n", num, num);
       else
         qh_fprintf(qh, fp, 9040, "VECT %d %d 1\n", num, num);
 
       for (i=num; i--; ) {
         if (i % 20 == 0)
           qh_fprintf(qh, fp, 9041, "\n");
         qh_fprintf(qh, fp, 9042, "1 ");
       }
       qh_fprintf(qh, fp, 9043, "# 1 point per line\n1 ");
       for (i=num-1; i--; ) { /* num at least 3 for D2 */
         if (i % 20 == 0)
           qh_fprintf(qh, fp, 9044, "\n");
         qh_fprintf(qh, fp, 9045, "0 ");
       }
       qh_fprintf(qh, fp, 9046, "# 1 color for all\n");
       FORALLpoints {
         if (!qh->DELAUNAY || !qh->ATinfinity || qh_pointid(qh, point) != qh->num_points-1) {
           if (qh->PRINTdim == 4)
             qh_printpoint(qh, fp, NULL, point);
             else
               qh_printpoint3(qh, fp, point);
         }
       }
       FOREACHpoint_(qh->other_points) {
         if (qh->PRINTdim == 4)
           qh_printpoint(qh, fp, NULL, point);
         else
           qh_printpoint3(qh, fp, point);
       }
       qh_fprintf(qh, fp, 9047, "0 1 1 1  # color of points\n");
     }
 
     if (qh->PRINTdim == 4  && !qh->PRINTnoplanes)
       /* 4dview loads up multiple 4OFF objects slowly */
       qh_fprintf(qh, fp, 9048, "4OFF %d %d 1\n", 3*qh->ridgeoutnum, qh->ridgeoutnum);
     qh->PRINTcradius= 2 * qh->DISTround;  /* include test DISTround */
     if (qh->PREmerge) {
       maximize_(qh->PRINTcradius, qh->premerge_centrum + qh->DISTround);
     }else if (qh->POSTmerge)
       maximize_(qh->PRINTcradius, qh->postmerge_centrum + qh->DISTround);
     qh->PRINTradius= qh->PRINTcradius;
     if (qh->PRINTspheres + qh->PRINTcoplanar)
       maximize_(qh->PRINTradius, qh->MAXabs_coord * qh_MINradius);
     if (qh->premerge_cos < REALmax/2) {
       maximize_(qh->PRINTradius, (1- qh->premerge_cos) * qh->MAXabs_coord);
     }else if (!qh->PREmerge && qh->POSTmerge && qh->postmerge_cos < REALmax/2) {
       maximize_(qh->PRINTradius, (1- qh->postmerge_cos) * qh->MAXabs_coord);
     }
     maximize_(qh->PRINTradius, qh->MINvisible);
     if (qh->JOGGLEmax < REALmax/2)
       qh->PRINTradius += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
     if (qh->PRINTdim != 4 &&
         (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {
       vertices= qh_facetvertices(qh, facetlist, facets, printall);
       if (qh->PRINTspheres && qh->PRINTdim <= 3)
         qh_printspheres(qh, fp, vertices, qh->PRINTradius);
       if (qh->PRINTcoplanar || qh->PRINTcentrums) {
         qh->firstcentrum= True;
         if (qh->PRINTcoplanar&& !qh->PRINTspheres) {
           FOREACHvertex_(vertices)
             qh_printpointvect2(qh, fp, vertex->point, NULL, qh->interior_point, qh->PRINTradius);
         }
         FORALLfacet_(facetlist) {
           if (!printall && qh_skipfacet(qh, facet))
             continue;
           if (!facet->normal)
             continue;
           if (qh->PRINTcentrums && qh->PRINTdim <= 3)
             qh_printcentrum(qh, fp, facet, qh->PRINTcradius);
           if (!qh->PRINTcoplanar)
             continue;
           FOREACHpoint_(facet->coplanarset)
             qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
           FOREACHpoint_(facet->outsideset)
             qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
         }
         FOREACHfacet_(facets) {
           if (!printall && qh_skipfacet(qh, facet))
             continue;
           if (!facet->normal)
             continue;
           if (qh->PRINTcentrums && qh->PRINTdim <= 3)
             qh_printcentrum(qh, fp, facet, qh->PRINTcradius);
           if (!qh->PRINTcoplanar)
             continue;
           FOREACHpoint_(facet->coplanarset)
             qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
           FOREACHpoint_(facet->outsideset)
             qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
         }
       }
       qh_settempfree(qh, &vertices);
     }
     qh->visit_id++; /* for printing hyperplane intersections */
     break;
   case qh_PRINTids:
     qh_fprintf(qh, fp, 9049, "%d\n", numfacets);
     break;
   case qh_PRINTincidences:
     if (qh->VORONOI && qh->PRINTprecision)
       qh_fprintf(qh, qh->ferr, 7053, "qhull warning: writing Delaunay.  Use 'p' or 'o' for Voronoi centers\n");
     qh->printoutvar= qh->vertex_id;  /* centrum id for non-simplicial facets */
     if (qh->hull_dim <= 3)
       qh_fprintf(qh, fp, 9050, "%d\n", numfacets);
     else
       qh_fprintf(qh, fp, 9051, "%d\n", numsimplicial+numridges);
     break;
   case qh_PRINTinner:
   case qh_PRINTnormals:
   case qh_PRINTouter:
     if (qh->CDDoutput)
       qh_fprintf(qh, fp, 9052, "%s | %s\nbegin\n    %d %d real\n", qh->rbox_command,
             qh->qhull_command, numfacets, qh->hull_dim+1);
     else
       qh_fprintf(qh, fp, 9053, "%d\n%d\n", qh->hull_dim+1, numfacets);
     break;
   case qh_PRINTmathematica:
   case qh_PRINTmaple:
     if (qh->hull_dim > 3)  /* qh_initbuffers also checks */
       goto LABELnoformat;
     if (qh->VORONOI)
       qh_fprintf(qh, qh->ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");
     if (format == qh_PRINTmaple) {
       if (qh->hull_dim == 2)
         qh_fprintf(qh, fp, 9054, "PLOT(CURVES(\n");
       else
         qh_fprintf(qh, fp, 9055, "PLOT3D(POLYGONS(\n");
     }else
       qh_fprintf(qh, fp, 9056, "{\n");
     qh->printoutvar= 0;   /* counts number of facets for notfirst */
     break;
   case qh_PRINTmerges:
     qh_fprintf(qh, fp, 9057, "%d\n", numfacets);
     break;
   case qh_PRINTpointintersect:
     qh_fprintf(qh, fp, 9058, "%d\n%d\n", qh->hull_dim, numfacets);
     break;
   case qh_PRINTneighbors:
     qh_fprintf(qh, fp, 9059, "%d\n", numfacets);
     break;
   case qh_PRINToff:
   case qh_PRINTtriangles:
     if (qh->VORONOI)
       goto LABELnoformat;
     num = qh->hull_dim;
     if (format == qh_PRINToff || qh->hull_dim == 2)
       qh_fprintf(qh, fp, 9060, "%d\n%d %d %d\n", num,
         qh->num_points+qh_setsize(qh, qh->other_points), numfacets, totneighbors/2);
     else { /* qh_PRINTtriangles */
       qh->printoutvar= qh->num_points+qh_setsize(qh, qh->other_points); /* first centrum */
       if (qh->DELAUNAY)
         num--;  /* drop last dimension */
       qh_fprintf(qh, fp, 9061, "%d\n%d %d %d\n", num, qh->printoutvar
         + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
     }
     FORALLpoints
       qh_printpointid(qh, qh->fout, NULL, num, point, -1);
     FOREACHpoint_(qh->other_points)
       qh_printpointid(qh, qh->fout, NULL, num, point, -1);
     if (format == qh_PRINTtriangles && qh->hull_dim > 2) {
       FORALLfacets {
         if (!facet->simplicial && facet->visitid)
           qh_printcenter(qh, qh->fout, format, NULL, facet);
       }
     }
     break;
   case qh_PRINTpointnearest:
     qh_fprintf(qh, fp, 9062, "%d\n", numcoplanars);
     break;
   case qh_PRINTpoints:
     if (!qh->VORONOI)
       goto LABELnoformat;
     if (qh->CDDoutput)
       qh_fprintf(qh, fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,
            qh->qhull_command, numfacets, qh->hull_dim);
     else
       qh_fprintf(qh, fp, 9064, "%d\n%d\n", qh->hull_dim-1, numfacets);
     break;
   case qh_PRINTvertices:
     qh_fprintf(qh, fp, 9065, "%d\n", numfacets);
     break;
   case qh_PRINTsummary:
   default:
   LABELnoformat:
     qh_fprintf(qh, qh->ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
          qh->hull_dim);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
 } /* printbegin */
 
 /*---------------------------------
 
   qh_printcenter(qh, fp, string, facet )
     print facet->center as centrum or Voronoi center
     string may be NULL.  Don't include '%' codes.
     nop if qh->CENTERtype neither CENTERvoronoi nor CENTERcentrum
     if upper envelope of Delaunay triangulation and point at-infinity
       prints qh_INFINITE instead;
 
   notes:
     defines facet->center if needed
     if format=PRINTgeom, adds a 0 if would otherwise be 2-d
     Same as QhullFacet::printCenter
 */
 void qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet) {
   int k, num;
 
   if (qh->CENTERtype != qh_ASvoronoi && qh->CENTERtype != qh_AScentrum)
     return;
   if (string)
     qh_fprintf(qh, fp, 9066, string);
   if (qh->CENTERtype == qh_ASvoronoi) {
     num= qh->hull_dim-1;
     if (!facet->normal || !facet->upperdelaunay || !qh->ATinfinity) {
       if (!facet->center)
         facet->center= qh_facetcenter(qh, facet->vertices);
       for (k=0; k < num; k++)
         qh_fprintf(qh, fp, 9067, qh_REAL_1, facet->center[k]);
     }else {
       for (k=0; k < num; k++)
         qh_fprintf(qh, fp, 9068, qh_REAL_1, qh_INFINITE);
     }
   }else /* qh->CENTERtype == qh_AScentrum */ {
     num= qh->hull_dim;
     if (format == qh_PRINTtriangles && qh->DELAUNAY)
       num--;
     if (!facet->center)
       facet->center= qh_getcentrum(qh, facet);
     for (k=0; k < num; k++)
       qh_fprintf(qh, fp, 9069, qh_REAL_1, facet->center[k]);
   }
   if (format == qh_PRINTgeom && num == 2)
     qh_fprintf(qh, fp, 9070, " 0\n");
   else
     qh_fprintf(qh, fp, 9071, "\n");
 } /* printcenter */
 
 /*---------------------------------
 
   qh_printcentrum(qh, fp, facet, radius )
     print centrum for a facet in OOGL format
     radius defines size of centrum
     2-d or 3-d only
 
   returns:
     defines facet->center if needed
 */
 void qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius) {
   pointT *centrum, *projpt;
   boolT tempcentrum= False;
   realT xaxis[4], yaxis[4], normal[4], dist;
   realT green[3]={0, 1, 0};
   vertexT *apex;
   int k;
 
   if (qh->CENTERtype == qh_AScentrum) {
     if (!facet->center)
       facet->center= qh_getcentrum(qh, facet);
     centrum= facet->center;
   }else {
     centrum= qh_getcentrum(qh, facet);
     tempcentrum= True;
   }
   qh_fprintf(qh, fp, 9072, "{appearance {-normal -edge normscale 0} ");
   if (qh->firstcentrum) {
     qh->firstcentrum= False;
     qh_fprintf(qh, fp, 9073, "{INST geom { define centrum CQUAD  # f%d\n\
 -0.3 -0.3 0.0001     0 0 1 1\n\
  0.3 -0.3 0.0001     0 0 1 1\n\
  0.3  0.3 0.0001     0 0 1 1\n\
 -0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
   }else
     qh_fprintf(qh, fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);
   apex= SETfirstt_(facet->vertices, vertexT);
   qh_distplane(qh, apex->point, facet, &dist);
   projpt= qh_projectpoint(qh, apex->point, facet, dist);
   for (k=qh->hull_dim; k--; ) {
     xaxis[k]= projpt[k] - centrum[k];
     normal[k]= facet->normal[k];
   }
   if (qh->hull_dim == 2) {
     xaxis[2]= 0;
     normal[2]= 0;
   }else if (qh->hull_dim == 4) {
     qh_projectdim3(qh, xaxis, xaxis);
     qh_projectdim3(qh, normal, normal);
     qh_normalize2(qh, normal, qh->PRINTdim, True, NULL, NULL);
   }
   qh_crossproduct(qh, 3, xaxis, normal, yaxis);
   qh_fprintf(qh, fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
   qh_fprintf(qh, fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
   qh_fprintf(qh, fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
   qh_printpoint3(qh, fp, centrum);
   qh_fprintf(qh, fp, 9078, "1 }}}\n");
   qh_memfree(qh, projpt, qh->normal_size);
   qh_printpointvect(qh, fp, centrum, facet->normal, NULL, radius, green);
   if (tempcentrum)
     qh_memfree(qh, centrum, qh->normal_size);
 } /* printcentrum */
 
 /*---------------------------------
 
   qh_printend(qh, fp, format )
     prints trailer for all output formats
 
   see:
     qh_printbegin() and qh_printafacet()
 
 */
 void qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int num;
   facetT *facet, **facetp;
 
   if (!qh->printoutnum)
     qh_fprintf(qh, qh->ferr, 7055, "qhull warning: no facets printed\n");
   switch (format) {
   case qh_PRINTgeom:
     if (qh->hull_dim == 4 && qh->DROPdim < 0  && !qh->PRINTnoplanes) {
       qh->visit_id++;
       num= 0;
       FORALLfacet_(facetlist)
         qh_printend4geom(qh, fp, facet,&num, printall);
       FOREACHfacet_(facets)
         qh_printend4geom(qh, fp, facet, &num, printall);
       if (num != qh->ridgeoutnum || qh->printoutvar != qh->ridgeoutnum) {
         qh_fprintf(qh, qh->ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh->ridgeoutnum, qh->printoutvar, num);
         qh_errexit(qh, qh_ERRqhull, NULL, NULL);
       }
     }else
       qh_fprintf(qh, fp, 9079, "}\n");
     break;
   case qh_PRINTinner:
   case qh_PRINTnormals:
   case qh_PRINTouter:
     if (qh->CDDoutput)
       qh_fprintf(qh, fp, 9080, "end\n");
     break;
   case qh_PRINTmaple:
     qh_fprintf(qh, fp, 9081, "));\n");
     break;
   case qh_PRINTmathematica:
     qh_fprintf(qh, fp, 9082, "}\n");
     break;
   case qh_PRINTpoints:
     if (qh->CDDoutput)
       qh_fprintf(qh, fp, 9083, "end\n");
     break;
   default:
     break;
   }
 } /* printend */
 
 /*---------------------------------
 
   qh_printend4geom(qh, fp, facet, numridges, printall )
     helper function for qh_printbegin/printend
 
   returns:
     number of printed ridges
 
   notes:
     just counts printed ridges if fp=NULL
     uses facet->visitid
     must agree with qh_printfacet4geom...
 
   design:
     computes color for facet from its normal
     prints each ridge of facet
 */
 void qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *nump, boolT printall) {
   realT color[3];
   int i, num= *nump;
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
 
   if (!printall && qh_skipfacet(qh, facet))
     return;
   if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
     return;
   if (!facet->normal)
     return;
   if (fp) {
     for (i=0; i < 3; i++) {
       color[i]= (facet->normal[i]+1.0)/2.0;
       maximize_(color[i], -1.0);
       minimize_(color[i], +1.0);
     }
   }
   facet->visitid= qh->visit_id;
   if (facet->simplicial) {
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh->visit_id) {
         if (fp)
           qh_fprintf(qh, fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
                  3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                  facet->id, neighbor->id);
         num++;
       }
     }
   }else {
     FOREACHridge_(facet->ridges) {
       neighbor= otherfacet_(ridge, facet);
       if (neighbor->visitid != qh->visit_id) {
         if (fp)
           qh_fprintf(qh, fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
                  3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
                  ridge->id, facet->id, neighbor->id);
         num++;
       }
     }
   }
   *nump= num;
 } /* printend4geom */
 
 /*---------------------------------
 
   qh_printextremes(qh, fp, facetlist, facets, printall )
     print extreme points for convex hulls or halfspace intersections
 
   notes:
     #points, followed by ids, one per line
 
     sorted by id
     same order as qh_printpoints_out if no coplanar/interior points
 */
 void qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   setT *vertices, *points;
   pointT *point;
   vertexT *vertex, **vertexp;
   int id;
   int numpoints=0, point_i, point_n;
   int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);
 
   points= qh_settemp(qh, allpoints);
   qh_setzero(qh, points, 0, allpoints);
   vertices= qh_facetvertices(qh, facetlist, facets, printall);
   FOREACHvertex_(vertices) {
     id= qh_pointid(qh, vertex->point);
     if (id >= 0) {
       SETelem_(points, id)= vertex->point;
       numpoints++;
     }
   }
   qh_settempfree(qh, &vertices);
   qh_fprintf(qh, fp, 9086, "%d\n", numpoints);
   FOREACHpoint_i_(qh, points) {
     if (point)
       qh_fprintf(qh, fp, 9087, "%d\n", point_i);
   }
   qh_settempfree(qh, &points);
 } /* printextremes */
 
 /*---------------------------------
 
   qh_printextremes_2d(qh, fp, facetlist, facets, printall )
     prints point ids for facets in qh_ORIENTclock order
 
   notes:
     #points, followed by ids, one per line
     if facetlist/facets are disjoint than the output includes skips
     errors if facets form a loop
     does not print coplanar points
 */
 void qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
   setT *vertices;
   facetT *facet, *startfacet, *nextfacet;
   vertexT *vertexA, *vertexB;
 
   qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh->visit_id */
   vertices= qh_facetvertices(qh, facetlist, facets, printall);
   qh_fprintf(qh, fp, 9088, "%d\n", qh_setsize(qh, vertices));
   qh_settempfree(qh, &vertices);
   if (!numfacets)
     return;
   facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
   qh->vertex_visit++;
   qh->visit_id++;
   do {
     if (facet->toporient ^ qh_ORIENTclock) {
       vertexA= SETfirstt_(facet->vertices, vertexT);
       vertexB= SETsecondt_(facet->vertices, vertexT);
       nextfacet= SETfirstt_(facet->neighbors, facetT);
     }else {
       vertexA= SETsecondt_(facet->vertices, vertexT);
       vertexB= SETfirstt_(facet->vertices, vertexT);
       nextfacet= SETsecondt_(facet->neighbors, facetT);
     }
     if (facet->visitid == qh->visit_id) {
       qh_fprintf(qh, qh->ferr, 6218, "Qhull internal error (qh_printextremes_2d): loop in facet list.  facet %d nextfacet %d\n",
                  facet->id, nextfacet->id);
       qh_errexit2(qh, qh_ERRqhull, facet, nextfacet);
     }
     if (facet->visitid) {
       if (vertexA->visitid != qh->vertex_visit) {
         vertexA->visitid= qh->vertex_visit;
         qh_fprintf(qh, fp, 9089, "%d\n", qh_pointid(qh, vertexA->point));
       }
       if (vertexB->visitid != qh->vertex_visit) {
         vertexB->visitid= qh->vertex_visit;
         qh_fprintf(qh, fp, 9090, "%d\n", qh_pointid(qh, vertexB->point));
       }
     }
     facet->visitid= qh->visit_id;
     facet= nextfacet;
   }while (facet && facet != startfacet);
 } /* printextremes_2d */
 
 /*---------------------------------
 
   qh_printextremes_d(qh, fp, facetlist, facets, printall )
     print extreme points of input sites for Delaunay triangulations
 
   notes:
     #points, followed by ids, one per line
 
     unordered
 */
 void qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   setT *vertices;
   vertexT *vertex, **vertexp;
   boolT upperseen, lowerseen;
   facetT *neighbor, **neighborp;
   int numpoints=0;
 
   vertices= qh_facetvertices(qh, facetlist, facets, printall);
   qh_vertexneighbors(qh);
   FOREACHvertex_(vertices) {
     upperseen= lowerseen= False;
     FOREACHneighbor_(vertex) {
       if (neighbor->upperdelaunay)
         upperseen= True;
       else
         lowerseen= True;
     }
     if (upperseen && lowerseen) {
       vertex->seen= True;
       numpoints++;
     }else
       vertex->seen= False;
   }
   qh_fprintf(qh, fp, 9091, "%d\n", numpoints);
   FOREACHvertex_(vertices) {
     if (vertex->seen)
       qh_fprintf(qh, fp, 9092, "%d\n", qh_pointid(qh, vertex->point));
   }
   qh_settempfree(qh, &vertices);
 } /* printextremes_d */
 
 /*---------------------------------
 
   qh_printfacet(qh, fp, facet )
     prints all fields of a facet to fp
 
   notes:
     ridges printed in neighbor order
 */
 void qh_printfacet(qhT *qh, FILE *fp, facetT *facet) {
 
   qh_printfacetheader(qh, fp, facet);
   if (facet->ridges)
     qh_printfacetridges(qh, fp, facet);
 } /* printfacet */
 
 
 /*---------------------------------
 
   qh_printfacet2geom(qh, fp, facet, color )
     print facet as part of a 2-d VECT for Geomview
 
     notes:
       assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
       mindist is calculated within io_r.c.  maxoutside is calculated elsewhere
       so a DISTround error may have occurred.
 */
 void qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
   pointT *point0, *point1;
   realT mindist, innerplane, outerplane;
   int k;
 
   qh_facet2point(qh, facet, &point0, &point1, &mindist);
   qh_geomplanes(qh, facet, &outerplane, &innerplane);
   if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
     qh_printfacet2geom_points(qh, fp, point0, point1, facet, outerplane, color);
   if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
                 outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
     for (k=3; k--; )
       color[k]= 1.0 - color[k];
     qh_printfacet2geom_points(qh, fp, point0, point1, facet, innerplane, color);
   }
   qh_memfree(qh, point1, qh->normal_size);
   qh_memfree(qh, point0, qh->normal_size);
 } /* printfacet2geom */
 
 /*---------------------------------
 
   qh_printfacet2geom_points(qh, fp, point1, point2, facet, offset, color )
     prints a 2-d facet as a VECT with 2 points at some offset.
     The points are on the facet's plane.
 */
 void qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,
                                facetT *facet, realT offset, realT color[3]) {
   pointT *p1= point1, *p2= point2;
 
   qh_fprintf(qh, fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);
   if (offset != 0.0) {
     p1= qh_projectpoint(qh, p1, facet, -offset);
     p2= qh_projectpoint(qh, p2, facet, -offset);
   }
   qh_fprintf(qh, fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
            p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
   if (offset != 0.0) {
     qh_memfree(qh, p1, qh->normal_size);
     qh_memfree(qh, p2, qh->normal_size);
   }
   qh_fprintf(qh, fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
 } /* printfacet2geom_points */
 
 
 /*---------------------------------
 
   qh_printfacet2math(qh, fp, facet, format, notfirst )
     print 2-d Maple or Mathematica output for a facet
     may be non-simplicial
 
   notes:
     use %16.8f since Mathematica 2.2 does not handle exponential format
     see qh_printfacet3math
 */
 void qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
   pointT *point0, *point1;
   realT mindist;
   const char *pointfmt;
 
   qh_facet2point(qh, facet, &point0, &point1, &mindist);
   if (notfirst)
     qh_fprintf(qh, fp, 9096, ",");
   if (format == qh_PRINTmaple)
     pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
   else
     pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
   qh_fprintf(qh, fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);
   qh_memfree(qh, point1, qh->normal_size);
   qh_memfree(qh, point0, qh->normal_size);
 } /* printfacet2math */
 
 
 /*---------------------------------
 
   qh_printfacet3geom_nonsimplicial(qh, fp, facet, color )
     print Geomview OFF for a 3-d nonsimplicial facet.
     if DOintersections, prints ridges to unvisited neighbors(qh->visit_id)
 
   notes
     uses facet->visitid for intersections and ridges
 */
 void qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
   ridgeT *ridge, **ridgep;
   setT *projectedpoints, *vertices;
   vertexT *vertex, **vertexp, *vertexA, *vertexB;
   pointT *projpt, *point, **pointp;
   facetT *neighbor;
   realT dist, outerplane, innerplane;
   int cntvertices, k;
   realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
 
   qh_geomplanes(qh, facet, &outerplane, &innerplane);
   vertices= qh_facet3vertex(qh, facet); /* oriented */
   cntvertices= qh_setsize(qh, vertices);
   projectedpoints= qh_settemp(qh, cntvertices);
   FOREACHvertex_(vertices) {
     zinc_(Zdistio);
     qh_distplane(qh, vertex->point, facet, &dist);
     projpt= qh_projectpoint(qh, vertex->point, facet, dist);
     qh_setappend(qh, &projectedpoints, projpt);
   }
   if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
     qh_printfacet3geom_points(qh, fp, projectedpoints, facet, outerplane, color);
   if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
                 outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
     for (k=3; k--; )
       color[k]= 1.0 - color[k];
     qh_printfacet3geom_points(qh, fp, projectedpoints, facet, innerplane, color);
   }
   FOREACHpoint_(projectedpoints)
     qh_memfree(qh, point, qh->normal_size);
   qh_settempfree(qh, &projectedpoints);
   qh_settempfree(qh, &vertices);
   if ((qh->DOintersections || qh->PRINTridges)
   && (!facet->visible || !qh->NEWfacets)) {
     facet->visitid= qh->visit_id;
     FOREACHridge_(facet->ridges) {
       neighbor= otherfacet_(ridge, facet);
       if (neighbor->visitid != qh->visit_id) {
         if (qh->DOintersections)
           qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, black);
         if (qh->PRINTridges) {
           vertexA= SETfirstt_(ridge->vertices, vertexT);
           vertexB= SETsecondt_(ridge->vertices, vertexT);
           qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);
         }
       }
     }
   }
 } /* printfacet3geom_nonsimplicial */
 
 /*---------------------------------
 
   qh_printfacet3geom_points(qh, fp, points, facet, offset )
     prints a 3-d facet as OFF Geomview object.
     offset is relative to the facet's hyperplane
     Facet is determined as a list of points
 */
 void qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
   int k, n= qh_setsize(qh, points), i;
   pointT *point, **pointp;
   setT *printpoints;
 
   qh_fprintf(qh, fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);
   if (offset != 0.0) {
     printpoints= qh_settemp(qh, n);
     FOREACHpoint_(points)
       qh_setappend(qh, &printpoints, qh_projectpoint(qh, point, facet, -offset));
   }else
     printpoints= points;
   FOREACHpoint_(printpoints) {
     for (k=0; k < qh->hull_dim; k++) {
       if (k == qh->DROPdim)
         qh_fprintf(qh, fp, 9099, "0 ");
       else
         qh_fprintf(qh, fp, 9100, "%8.4g ", point[k]);
     }
     if (printpoints != points)
       qh_memfree(qh, point, qh->normal_size);
     qh_fprintf(qh, fp, 9101, "\n");
   }
   if (printpoints != points)
     qh_settempfree(qh, &printpoints);
   qh_fprintf(qh, fp, 9102, "%d ", n);
   for (i=0; i < n; i++)
     qh_fprintf(qh, fp, 9103, "%d ", i);
   qh_fprintf(qh, fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
 } /* printfacet3geom_points */
 
 
 /*---------------------------------
 
   qh_printfacet3geom_simplicial(qh, )
     print Geomview OFF for a 3-d simplicial facet.
 
   notes:
     may flip color
     uses facet->visitid for intersections and ridges
 
     assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
     innerplane may be off by qh->DISTround.  Maxoutside is calculated elsewhere
     so a DISTround error may have occurred.
 */
 void qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
   setT *points, *vertices;
   vertexT *vertex, **vertexp, *vertexA, *vertexB;
   facetT *neighbor, **neighborp;
   realT outerplane, innerplane;
   realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
   int k;
 
   qh_geomplanes(qh, facet, &outerplane, &innerplane);
   vertices= qh_facet3vertex(qh, facet);
   points= qh_settemp(qh, qh->TEMPsize);
   FOREACHvertex_(vertices)
     qh_setappend(qh, &points, vertex->point);
   if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
     qh_printfacet3geom_points(qh, fp, points, facet, outerplane, color);
   if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
               outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
     for (k=3; k--; )
       color[k]= 1.0 - color[k];
     qh_printfacet3geom_points(qh, fp, points, facet, innerplane, color);
   }
   qh_settempfree(qh, &points);
   qh_settempfree(qh, &vertices);
   if ((qh->DOintersections || qh->PRINTridges)
   && (!facet->visible || !qh->NEWfacets)) {
     facet->visitid= qh->visit_id;
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh->visit_id) {
         vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
                           SETindex_(facet->neighbors, neighbor), 0);
         if (qh->DOintersections)
            qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, black);
         if (qh->PRINTridges) {
           vertexA= SETfirstt_(vertices, vertexT);
           vertexB= SETsecondt_(vertices, vertexT);
           qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);
         }
         qh_setfree(qh, &vertices);
       }
     }
   }
 } /* printfacet3geom_simplicial */
 
 /*---------------------------------
 
   qh_printfacet3math(qh, fp, facet, notfirst )
     print 3-d Maple or Mathematica output for a facet
 
   notes:
     may be non-simplicial
     use %16.8f since Mathematica 2.2 does not handle exponential format
     see qh_printfacet2math
 */
 void qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
   vertexT *vertex, **vertexp;
   setT *points, *vertices;
   pointT *point, **pointp;
   boolT firstpoint= True;
   realT dist;
   const char *pointfmt, *endfmt;
 
   if (notfirst)
     qh_fprintf(qh, fp, 9105, ",\n");
   vertices= qh_facet3vertex(qh, facet);
   points= qh_settemp(qh, qh_setsize(qh, vertices));
   FOREACHvertex_(vertices) {
     zinc_(Zdistio);
     qh_distplane(qh, vertex->point, facet, &dist);
     point= qh_projectpoint(qh, vertex->point, facet, dist);
     qh_setappend(qh, &points, point);
   }
   if (format == qh_PRINTmaple) {
     qh_fprintf(qh, fp, 9106, "[");
     pointfmt= "[%16.8f, %16.8f, %16.8f]";
     endfmt= "]";
   }else {
     qh_fprintf(qh, fp, 9107, "Polygon[{");
     pointfmt= "{%16.8f, %16.8f, %16.8f}";
     endfmt= "}]";
   }
   FOREACHpoint_(points) {
     if (firstpoint)
       firstpoint= False;
     else
       qh_fprintf(qh, fp, 9108, ",\n");
     qh_fprintf(qh, fp, 9109, pointfmt, point[0], point[1], point[2]);
   }
   FOREACHpoint_(points)
     qh_memfree(qh, point, qh->normal_size);
   qh_settempfree(qh, &points);
   qh_settempfree(qh, &vertices);
   qh_fprintf(qh, fp, 9110, endfmt);
 } /* printfacet3math */
 
 
 /*---------------------------------
 
   qh_printfacet3vertex(qh, fp, facet, format )
     print vertices in a 3-d facet as point ids
 
   notes:
     prints number of vertices first if format == qh_PRINToff
     the facet may be non-simplicial
 */
 void qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {
   vertexT *vertex, **vertexp;
   setT *vertices;
 
   vertices= qh_facet3vertex(qh, facet);
   if (format == qh_PRINToff)
     qh_fprintf(qh, fp, 9111, "%d ", qh_setsize(qh, vertices));
   FOREACHvertex_(vertices)
     qh_fprintf(qh, fp, 9112, "%d ", qh_pointid(qh, vertex->point));
   qh_fprintf(qh, fp, 9113, "\n");
   qh_settempfree(qh, &vertices);
 } /* printfacet3vertex */
 
 
 /*---------------------------------
 
   qh_printfacet4geom_nonsimplicial(qh, )
     print Geomview 4OFF file for a 4d nonsimplicial facet
     prints all ridges to unvisited neighbors (qh.visit_id)
     if qh.DROPdim
       prints in OFF format
 
   notes:
     must agree with printend4geom()
 */
 void qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
   facetT *neighbor;
   ridgeT *ridge, **ridgep;
   vertexT *vertex, **vertexp;
   pointT *point;
   int k;
   realT dist;
 
   facet->visitid= qh->visit_id;
   if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
     return;
   FOREACHridge_(facet->ridges) {
     neighbor= otherfacet_(ridge, facet);
     if (neighbor->visitid == qh->visit_id)
       continue;
     if (qh->PRINTtransparent && !neighbor->good)
       continue;
     if (qh->DOintersections)
       qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, color);
     else {
       if (qh->DROPdim >= 0)
         qh_fprintf(qh, fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);
       else {
         qh->printoutvar++;
         qh_fprintf(qh, fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
       }
       FOREACHvertex_(ridge->vertices) {
         zinc_(Zdistio);
         qh_distplane(qh, vertex->point,facet, &dist);
         point=qh_projectpoint(qh, vertex->point,facet, dist);
         for (k=0; k < qh->hull_dim; k++) {
           if (k != qh->DROPdim)
             qh_fprintf(qh, fp, 9116, "%8.4g ", point[k]);
         }
         qh_fprintf(qh, fp, 9117, "\n");
         qh_memfree(qh, point, qh->normal_size);
       }
       if (qh->DROPdim >= 0)
         qh_fprintf(qh, fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
     }
   }
 } /* printfacet4geom_nonsimplicial */
 
 
 /*---------------------------------
 
   qh_printfacet4geom_simplicial(qh, fp, facet, color )
     print Geomview 4OFF file for a 4d simplicial facet
     prints triangles for unvisited neighbors (qh.visit_id)
 
   notes:
     must agree with printend4geom()
 */
 void qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
   setT *vertices;
   facetT *neighbor, **neighborp;
   vertexT *vertex, **vertexp;
   int k;
 
   facet->visitid= qh->visit_id;
   if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
     return;
   FOREACHneighbor_(facet) {
     if (neighbor->visitid == qh->visit_id)
       continue;
     if (qh->PRINTtransparent && !neighbor->good)
       continue;
     vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
                           SETindex_(facet->neighbors, neighbor), 0);
     if (qh->DOintersections)
       qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, color);
     else {
       if (qh->DROPdim >= 0)
         qh_fprintf(qh, fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",
                 facet->id, neighbor->id);
       else {
         qh->printoutvar++;
         qh_fprintf(qh, fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);
       }
       FOREACHvertex_(vertices) {
         for (k=0; k < qh->hull_dim; k++) {
           if (k != qh->DROPdim)
             qh_fprintf(qh, fp, 9121, "%8.4g ", vertex->point[k]);
         }
         qh_fprintf(qh, fp, 9122, "\n");
       }
       if (qh->DROPdim >= 0)
         qh_fprintf(qh, fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
     }
     qh_setfree(qh, &vertices);
   }
 } /* printfacet4geom_simplicial */
 
 
 /*---------------------------------
 
   qh_printfacetNvertex_nonsimplicial(qh, fp, facet, id, format )
     print vertices for an N-d non-simplicial facet
     triangulates each ridge to the id
 */
 void qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format) {
   vertexT *vertex, **vertexp;
   ridgeT *ridge, **ridgep;
 
   if (facet->visible && qh->NEWfacets)
     return;
   FOREACHridge_(facet->ridges) {
     if (format == qh_PRINTtriangles)
       qh_fprintf(qh, fp, 9124, "%d ", qh->hull_dim);
     qh_fprintf(qh, fp, 9125, "%d ", id);
     if ((ridge->top == facet) ^ qh_ORIENTclock) {
       FOREACHvertex_(ridge->vertices)
         qh_fprintf(qh, fp, 9126, "%d ", qh_pointid(qh, vertex->point));
     }else {
       FOREACHvertexreverse12_(ridge->vertices)
         qh_fprintf(qh, fp, 9127, "%d ", qh_pointid(qh, vertex->point));
     }
     qh_fprintf(qh, fp, 9128, "\n");
   }
 } /* printfacetNvertex_nonsimplicial */
 
 
 /*---------------------------------
 
   qh_printfacetNvertex_simplicial(qh, fp, facet, format )
     print vertices for an N-d simplicial facet
     prints vertices for non-simplicial facets
       2-d facets (orientation preserved by qh_mergefacet2d)
       PRINToff ('o') for 4-d and higher
 */
 void qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {
   vertexT *vertex, **vertexp;
 
   if (format == qh_PRINToff || format == qh_PRINTtriangles)
     qh_fprintf(qh, fp, 9129, "%d ", qh_setsize(qh, facet->vertices));
   if ((facet->toporient ^ qh_ORIENTclock)
   || (qh->hull_dim > 2 && !facet->simplicial)) {
     FOREACHvertex_(facet->vertices)
       qh_fprintf(qh, fp, 9130, "%d ", qh_pointid(qh, vertex->point));
   }else {
     FOREACHvertexreverse12_(facet->vertices)
       qh_fprintf(qh, fp, 9131, "%d ", qh_pointid(qh, vertex->point));
   }
   qh_fprintf(qh, fp, 9132, "\n");
 } /* printfacetNvertex_simplicial */
 
 
 /*---------------------------------
 
   qh_printfacetheader(qh, fp, facet )
     prints header fields of a facet to fp
 
   notes:
     for 'f' output and debugging
     Same as QhullFacet::printHeader()
 */
 void qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet) {
   pointT *point, **pointp, *furthest;
   facetT *neighbor, **neighborp;
   realT dist;
 
   if (facet == qh_MERGEridge) {
     qh_fprintf(qh, fp, 9133, " MERGEridge\n");
     return;
   }else if (facet == qh_DUPLICATEridge) {
     qh_fprintf(qh, fp, 9134, " DUPLICATEridge\n");
     return;
   }else if (!facet) {
     qh_fprintf(qh, fp, 9135, " NULLfacet\n");
     return;
   }
   qh->old_randomdist= qh->RANDOMdist;
   qh->RANDOMdist= False;
   qh_fprintf(qh, fp, 9136, "- f%d\n", facet->id);
   qh_fprintf(qh, fp, 9137, "    - flags:");
   if (facet->toporient)
     qh_fprintf(qh, fp, 9138, " top");
   else
     qh_fprintf(qh, fp, 9139, " bottom");
   if (facet->simplicial)
     qh_fprintf(qh, fp, 9140, " simplicial");
   if (facet->tricoplanar)
     qh_fprintf(qh, fp, 9141, " tricoplanar");
   if (facet->upperdelaunay)
     qh_fprintf(qh, fp, 9142, " upperDelaunay");
   if (facet->visible)
     qh_fprintf(qh, fp, 9143, " visible");
   if (facet->newfacet)
     qh_fprintf(qh, fp, 9144, " new");
   if (facet->tested)
     qh_fprintf(qh, fp, 9145, " tested");
   if (!facet->good)
     qh_fprintf(qh, fp, 9146, " notG");
   if (facet->seen)
     qh_fprintf(qh, fp, 9147, " seen");
   if (facet->coplanar)
     qh_fprintf(qh, fp, 9148, " coplanar");
   if (facet->mergehorizon)
     qh_fprintf(qh, fp, 9149, " mergehorizon");
   if (facet->keepcentrum)
     qh_fprintf(qh, fp, 9150, " keepcentrum");
   if (facet->dupridge)
     qh_fprintf(qh, fp, 9151, " dupridge");
   if (facet->mergeridge && !facet->mergeridge2)
     qh_fprintf(qh, fp, 9152, " mergeridge1");
   if (facet->mergeridge2)
     qh_fprintf(qh, fp, 9153, " mergeridge2");
   if (facet->newmerge)
     qh_fprintf(qh, fp, 9154, " newmerge");
   if (facet->flipped)
     qh_fprintf(qh, fp, 9155, " flipped");
   if (facet->notfurthest)
     qh_fprintf(qh, fp, 9156, " notfurthest");
   if (facet->degenerate)
     qh_fprintf(qh, fp, 9157, " degenerate");
   if (facet->redundant)
     qh_fprintf(qh, fp, 9158, " redundant");
   qh_fprintf(qh, fp, 9159, "\n");
   if (facet->isarea)
     qh_fprintf(qh, fp, 9160, "    - area: %2.2g\n", facet->f.area);
   else if (qh->NEWfacets && facet->visible && facet->f.replace)
     qh_fprintf(qh, fp, 9161, "    - replacement: f%d\n", facet->f.replace->id);
   else if (facet->newfacet) {
     if (facet->f.samecycle && facet->f.samecycle != facet)
       qh_fprintf(qh, fp, 9162, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
   }else if (facet->tricoplanar /* !isarea */) {
     if (facet->f.triowner)
       qh_fprintf(qh, fp, 9163, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
   }else if (facet->f.newcycle)
     qh_fprintf(qh, fp, 9164, "    - was horizon to f%d\n", facet->f.newcycle->id);
   if (facet->nummerge)
     qh_fprintf(qh, fp, 9165, "    - merges: %d\n", facet->nummerge);
   qh_printpointid(qh, fp, "    - normal: ", qh->hull_dim, facet->normal, -1);
   qh_fprintf(qh, fp, 9166, "    - offset: %10.7g\n", facet->offset);
   if (qh->CENTERtype == qh_ASvoronoi || facet->center)
     qh_printcenter(qh, fp, qh_PRINTfacets, "    - center: ", facet);
 #if qh_MAXoutside
   if (facet->maxoutside > qh->DISTround)
     qh_fprintf(qh, fp, 9167, "    - maxoutside: %10.7g\n", facet->maxoutside);
 #endif
   if (!SETempty_(facet->outsideset)) {
     furthest= (pointT*)qh_setlast(facet->outsideset);
     if (qh_setsize(qh, facet->outsideset) < 6) {
       qh_fprintf(qh, fp, 9168, "    - outside set(furthest p%d):\n", qh_pointid(qh, furthest));
       FOREACHpoint_(facet->outsideset)
         qh_printpoint(qh, fp, "     ", point);
     }else if (qh_setsize(qh, facet->outsideset) < 21) {
       qh_printpoints(qh, fp, "    - outside set:", facet->outsideset);
     }else {
       qh_fprintf(qh, fp, 9169, "    - outside set:  %d points.", qh_setsize(qh, facet->outsideset));
       qh_printpoint(qh, fp, "  Furthest", furthest);
     }
 #if !qh_COMPUTEfurthest
     qh_fprintf(qh, fp, 9170, "    - furthest distance= %2.2g\n", facet->furthestdist);
 #endif
   }
   if (!SETempty_(facet->coplanarset)) {
     furthest= (pointT*)qh_setlast(facet->coplanarset);
     if (qh_setsize(qh, facet->coplanarset) < 6) {
       qh_fprintf(qh, fp, 9171, "    - coplanar set(furthest p%d):\n", qh_pointid(qh, furthest));
       FOREACHpoint_(facet->coplanarset)
         qh_printpoint(qh, fp, "     ", point);
     }else if (qh_setsize(qh, facet->coplanarset) < 21) {
       qh_printpoints(qh, fp, "    - coplanar set:", facet->coplanarset);
     }else {
       qh_fprintf(qh, fp, 9172, "    - coplanar set:  %d points.", qh_setsize(qh, facet->coplanarset));
       qh_printpoint(qh, fp, "  Furthest", furthest);
     }
     zinc_(Zdistio);
     qh_distplane(qh, furthest, facet, &dist);
     qh_fprintf(qh, fp, 9173, "      furthest distance= %2.2g\n", dist);
   }
   qh_printvertices(qh, fp, "    - vertices:", facet->vertices);
   qh_fprintf(qh, fp, 9174, "    - neighboring facets:");
   FOREACHneighbor_(facet) {
     if (neighbor == qh_MERGEridge)
       qh_fprintf(qh, fp, 9175, " MERGE");
     else if (neighbor == qh_DUPLICATEridge)
       qh_fprintf(qh, fp, 9176, " DUP");
     else
       qh_fprintf(qh, fp, 9177, " f%d", neighbor->id);
   }
   qh_fprintf(qh, fp, 9178, "\n");
   qh->RANDOMdist= qh->old_randomdist;
 } /* printfacetheader */
 
 
 /*---------------------------------
 
   qh_printfacetridges(qh, fp, facet )
     prints ridges of a facet to fp
 
   notes:
     ridges printed in neighbor order
     assumes the ridges exist
     for 'f' output
     same as QhullFacet::printRidges
 */
 void qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet) {
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int numridges= 0;
 
 
   if (facet->visible && qh->NEWfacets) {
     qh_fprintf(qh, fp, 9179, "    - ridges(ids may be garbage):");
     FOREACHridge_(facet->ridges)
       qh_fprintf(qh, fp, 9180, " r%d", ridge->id);
     qh_fprintf(qh, fp, 9181, "\n");
   }else {
     qh_fprintf(qh, fp, 9182, "    - ridges:\n");
     FOREACHridge_(facet->ridges)
       ridge->seen= False;
     if (qh->hull_dim == 3) {
       ridge= SETfirstt_(facet->ridges, ridgeT);
       while (ridge && !ridge->seen) {
         ridge->seen= True;
         qh_printridge(qh, fp, ridge);
         numridges++;
         ridge= qh_nextridge3d(qh, ridge, facet, NULL);
         }
     }else {
       FOREACHneighbor_(facet) {
         FOREACHridge_(facet->ridges) {
           if (otherfacet_(ridge,facet) == neighbor) {
             ridge->seen= True;
             qh_printridge(qh, fp, ridge);
             numridges++;
           }
         }
       }
     }
     if (numridges != qh_setsize(qh, facet->ridges)) {
       qh_fprintf(qh, fp, 9183, "     - all ridges:");
       FOREACHridge_(facet->ridges)
         qh_fprintf(qh, fp, 9184, " r%d", ridge->id);
         qh_fprintf(qh, fp, 9185, "\n");
     }
     FOREACHridge_(facet->ridges) {
       if (!ridge->seen)
         qh_printridge(qh, fp, ridge);
     }
   }
 } /* printfacetridges */
 
 /*---------------------------------
 
   qh_printfacets(qh, fp, format, facetlist, facets, printall )
     prints facetlist and/or facet set in output format
 
   notes:
     also used for specialized formats ('FO' and summary)
     turns off 'Rn' option since want actual numbers
 */
 void qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
   facetT *facet, **facetp;
   setT *vertices;
   coordT *center;
   realT outerplane, innerplane;
 
   qh->old_randomdist= qh->RANDOMdist;
   qh->RANDOMdist= False;
   if (qh->CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
     qh_fprintf(qh, qh->ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
   if (format == qh_PRINTnone)
     ; /* print nothing */
   else if (format == qh_PRINTaverage) {
     vertices= qh_facetvertices(qh, facetlist, facets, printall);
     center= qh_getcenter(qh, vertices);
     qh_fprintf(qh, fp, 9186, "%d 1\n", qh->hull_dim);
     qh_printpointid(qh, fp, NULL, qh->hull_dim, center, -1);
     qh_memfree(qh, center, qh->normal_size);
     qh_settempfree(qh, &vertices);
   }else if (format == qh_PRINTextremes) {
     if (qh->DELAUNAY)
       qh_printextremes_d(qh, fp, facetlist, facets, printall);
     else if (qh->hull_dim == 2)
       qh_printextremes_2d(qh, fp, facetlist, facets, printall);
     else
       qh_printextremes(qh, fp, facetlist, facets, printall);
   }else if (format == qh_PRINToptions)
     qh_fprintf(qh, fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
   else if (format == qh_PRINTpoints && !qh->VORONOI)
     qh_printpoints_out(qh, fp, facetlist, facets, printall);
   else if (format == qh_PRINTqhull)
     qh_fprintf(qh, fp, 9188, "%s | %s\n", qh->rbox_command, qh->qhull_command);
   else if (format == qh_PRINTsize) {
     qh_fprintf(qh, fp, 9189, "0\n2 ");
     qh_fprintf(qh, fp, 9190, qh_REAL_1, qh->totarea);
     qh_fprintf(qh, fp, 9191, qh_REAL_1, qh->totvol);
     qh_fprintf(qh, fp, 9192, "\n");
   }else if (format == qh_PRINTsummary) {
     qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
     vertices= qh_facetvertices(qh, facetlist, facets, printall);
     qh_fprintf(qh, fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh->hull_dim,
                 qh->num_points + qh_setsize(qh, qh->other_points),
                 qh->num_vertices, qh->num_facets - qh->num_visible,
                 qh_setsize(qh, vertices), numfacets, numcoplanars,
                 numfacets - numsimplicial, zzval_(Zdelvertextot),
                 numtricoplanars);
     qh_settempfree(qh, &vertices);
     qh_outerinner(qh, NULL, &outerplane, &innerplane);
     qh_fprintf(qh, fp, 9194, qh_REAL_2n, outerplane, innerplane);
   }else if (format == qh_PRINTvneighbors)
     qh_printvneighbors(qh, fp, facetlist, facets, printall);
   else if (qh->VORONOI && format == qh_PRINToff)
     qh_printvoronoi(qh, fp, format, facetlist, facets, printall);
   else if (qh->VORONOI && format == qh_PRINTgeom) {
     qh_printbegin(qh, fp, format, facetlist, facets, printall);
     qh_printvoronoi(qh, fp, format, facetlist, facets, printall);
     qh_printend(qh, fp, format, facetlist, facets, printall);
   }else if (qh->VORONOI
   && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
     qh_printvdiagram(qh, fp, format, facetlist, facets, printall);
   else {
     qh_printbegin(qh, fp, format, facetlist, facets, printall);
     FORALLfacet_(facetlist)
       qh_printafacet(qh, fp, format, facet, printall);
     FOREACHfacet_(facets)
       qh_printafacet(qh, fp, format, facet, printall);
     qh_printend(qh, fp, format, facetlist, facets, printall);
   }
   qh->RANDOMdist= qh->old_randomdist;
 } /* printfacets */
 
 
 /*---------------------------------
 
   qh_printhyperplaneintersection(qh, fp, facet1, facet2, vertices, color )
     print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
 */
 void qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,
                    setT *vertices, realT color[3]) {
   realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
   vertexT *vertex, **vertexp;
   int i, k;
   boolT nearzero1, nearzero2;
 
   costheta= qh_getangle(qh, facet1->normal, facet2->normal);
   denominator= 1 - costheta * costheta;
   i= qh_setsize(qh, vertices);
   if (qh->hull_dim == 3)
     qh_fprintf(qh, fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);
   else if (qh->hull_dim == 4 && qh->DROPdim >= 0)
     qh_fprintf(qh, fp, 9196, "OFF 3 1 1 ");
   else
     qh->printoutvar++;
   qh_fprintf(qh, fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);
   mindenom= 1 / (10.0 * qh->MAXabs_coord);
   FOREACHvertex_(vertices) {
     zadd_(Zdistio, 2);
     qh_distplane(qh, vertex->point, facet1, &dist1);
     qh_distplane(qh, vertex->point, facet2, &dist2);
     s= qh_divzero(qh, -dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
     t= qh_divzero(qh, -dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
     if (nearzero1 || nearzero2)
       s= t= 0.0;
     for (k=qh->hull_dim; k--; )
       p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
     if (qh->PRINTdim <= 3) {
       qh_projectdim3(qh, p, p);
       qh_fprintf(qh, fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
     }else
       qh_fprintf(qh, fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
     if (nearzero1+nearzero2)
       qh_fprintf(qh, fp, 9200, "p%d(coplanar facets)\n", qh_pointid(qh, vertex->point));
     else
       qh_fprintf(qh, fp, 9201, "projected p%d\n", qh_pointid(qh, vertex->point));
   }
   if (qh->hull_dim == 3)
     qh_fprintf(qh, fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
   else if (qh->hull_dim == 4 && qh->DROPdim >= 0)
     qh_fprintf(qh, fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
 } /* printhyperplaneintersection */
 
 /*---------------------------------
 
   qh_printline3geom(qh, fp, pointA, pointB, color )
     prints a line as a VECT
     prints 0's for qh.DROPdim
 
   notes:
     if pointA == pointB,
       it's a 1 point VECT
 */
 void qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
   int k;
   realT pA[4], pB[4];
 
   qh_projectdim3(qh, pointA, pA);
   qh_projectdim3(qh, pointB, pB);
   if ((fabs(pA[0] - pB[0]) > 1e-3) ||
       (fabs(pA[1] - pB[1]) > 1e-3) ||
       (fabs(pA[2] - pB[2]) > 1e-3)) {
     qh_fprintf(qh, fp, 9204, "VECT 1 2 1 2 1\n");
     for (k=0; k < 3; k++)
        qh_fprintf(qh, fp, 9205, "%8.4g ", pB[k]);
     qh_fprintf(qh, fp, 9206, " # p%d\n", qh_pointid(qh, pointB));
   }else
     qh_fprintf(qh, fp, 9207, "VECT 1 1 1 1 1\n");
   for (k=0; k < 3; k++)
     qh_fprintf(qh, fp, 9208, "%8.4g ", pA[k]);
   qh_fprintf(qh, fp, 9209, " # p%d\n", qh_pointid(qh, pointA));
   qh_fprintf(qh, fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
 }
 
 /*---------------------------------
 
   qh_printneighborhood(qh, fp, format, facetA, facetB, printall )
     print neighborhood of one or two facets
 
   notes:
     calls qh_findgood_all()
     bumps qh.visit_id
 */
 void qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {
   facetT *neighbor, **neighborp, *facet;
   setT *facets;
 
   if (format == qh_PRINTnone)
     return;
   qh_findgood_all(qh, qh->facet_list);
   if (facetA == facetB)
     facetB= NULL;
   facets= qh_settemp(qh, 2*(qh_setsize(qh, facetA->neighbors)+1));
   qh->visit_id++;
   for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
     if (facet->visitid != qh->visit_id) {
       facet->visitid= qh->visit_id;
       qh_setappend(qh, &facets, facet);
     }
     FOREACHneighbor_(facet) {
       if (neighbor->visitid == qh->visit_id)
         continue;
       neighbor->visitid= qh->visit_id;
       if (printall || !qh_skipfacet(qh, neighbor))
         qh_setappend(qh, &facets, neighbor);
     }
   }
   qh_printfacets(qh, fp, format, NULL, facets, printall);
   qh_settempfree(qh, &facets);
 } /* printneighborhood */
 
 /*---------------------------------
 
   qh_printpoint(qh, fp, string, point )
   qh_printpointid(qh, fp, string, dim, point, id )
     prints the coordinates of a point
 
   returns:
     if string is defined
       prints 'string p%d' (skips p%d if id=-1)
 
   notes:
     nop if point is NULL
     prints id unless it is undefined (-1)
     Same as QhullPoint's printPoint
 */
 void qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point) {
   int id= qh_pointid(qh, point);
 
   qh_printpointid(qh, fp, string, qh->hull_dim, point, id);
 } /* printpoint */
 
 void qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id) {
   int k;
   realT r; /*bug fix*/
 
   if (!point)
     return;
   if (string) {
     qh_fprintf(qh, fp, 9211, "%s", string);
    if (id != -1)
       qh_fprintf(qh, fp, 9212, " p%d: ", id);
   }
   for (k=dim; k--; ) {
     r= *point++;
     if (string)
       qh_fprintf(qh, fp, 9213, " %8.4g", r);
     else
       qh_fprintf(qh, fp, 9214, qh_REAL_1, r);
   }
   qh_fprintf(qh, fp, 9215, "\n");
 } /* printpointid */
 
 /*---------------------------------
 
   qh_printpoint3(qh, fp, point )
     prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
 */
 void qh_printpoint3(qhT *qh, FILE *fp, pointT *point) {
   int k;
   realT p[4];
 
   qh_projectdim3(qh, point, p);
   for (k=0; k < 3; k++)
     qh_fprintf(qh, fp, 9216, "%8.4g ", p[k]);
   qh_fprintf(qh, fp, 9217, " # p%d\n", qh_pointid(qh, point));
 } /* printpoint3 */
 
 /*----------------------------------------
 -printpoints- print pointids for a set of points starting at index
    see geom_r.c
 */
 
 /*---------------------------------
 
   qh_printpoints_out(qh, fp, facetlist, facets, printall )
     prints vertices, coplanar/inside points, for facets by their point coordinates
     allows qh.CDDoutput
 
   notes:
     same format as qhull input
     if no coplanar/interior points,
       same order as qh_printextremes
 */
 void qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
   int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);
   int numpoints=0, point_i, point_n;
   setT *vertices, *points;
   facetT *facet, **facetp;
   pointT *point, **pointp;
   vertexT *vertex, **vertexp;
   int id;
 
   points= qh_settemp(qh, allpoints);
   qh_setzero(qh, points, 0, allpoints);
   vertices= qh_facetvertices(qh, facetlist, facets, printall);
   FOREACHvertex_(vertices) {
     id= qh_pointid(qh, vertex->point);
     if (id >= 0)
       SETelem_(points, id)= vertex->point;
   }
   if (qh->KEEPinside || qh->KEEPcoplanar || qh->KEEPnearinside) {
     FORALLfacet_(facetlist) {
       if (!printall && qh_skipfacet(qh, facet))
         continue;
       FOREACHpoint_(facet->coplanarset) {
         id= qh_pointid(qh, point);
         if (id >= 0)
           SETelem_(points, id)= point;
       }
     }
     FOREACHfacet_(facets) {
       if (!printall && qh_skipfacet(qh, facet))
         continue;
       FOREACHpoint_(facet->coplanarset) {
         id= qh_pointid(qh, point);
         if (id >= 0)
           SETelem_(points, id)= point;
       }
     }
   }
   qh_settempfree(qh, &vertices);
   FOREACHpoint_i_(qh, points) {
     if (point)
       numpoints++;
   }
   if (qh->CDDoutput)
     qh_fprintf(qh, fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,
              qh->qhull_command, numpoints, qh->hull_dim + 1);
   else
     qh_fprintf(qh, fp, 9219, "%d\n%d\n", qh->hull_dim, numpoints);
   FOREACHpoint_i_(qh, points) {
     if (point) {
       if (qh->CDDoutput)
         qh_fprintf(qh, fp, 9220, "1 ");
       qh_printpoint(qh, fp, NULL, point);
     }
   }
   if (qh->CDDoutput)
     qh_fprintf(qh, fp, 9221, "end\n");
   qh_settempfree(qh, &points);
 } /* printpoints_out */
 
 
 /*---------------------------------
 
   qh_printpointvect(qh, fp, point, normal, center, radius, color )
     prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
 */
 void qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
   realT diff[4], pointA[4];
   int k;
 
   for (k=qh->hull_dim; k--; ) {
     if (center)
       diff[k]= point[k]-center[k];
     else if (normal)
       diff[k]= normal[k];
     else
       diff[k]= 0;
   }
   if (center)
     qh_normalize2(qh, diff, qh->hull_dim, True, NULL, NULL);
   for (k=qh->hull_dim; k--; )
     pointA[k]= point[k]+diff[k] * radius;
   qh_printline3geom(qh, fp, point, pointA, color);
 } /* printpointvect */
 
 /*---------------------------------
 
   qh_printpointvect2(qh, fp, point, normal, center, radius )
     prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
 */
 void qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
   realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
 
   qh_printpointvect(qh, fp, point, normal, center, radius, red);
   qh_printpointvect(qh, fp, point, normal, center, -radius, yellow);
 } /* printpointvect2 */
 
 /*---------------------------------
 
   qh_printridge(qh, fp, ridge )
     prints the information in a ridge
 
   notes:
     for qh_printfacetridges()
     same as operator<< [QhullRidge.cpp]
 */
 void qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge) {
 
   qh_fprintf(qh, fp, 9222, "     - r%d", ridge->id);
   if (ridge->tested)
     qh_fprintf(qh, fp, 9223, " tested");
   if (ridge->nonconvex)
     qh_fprintf(qh, fp, 9224, " nonconvex");
   qh_fprintf(qh, fp, 9225, "\n");
   qh_printvertices(qh, fp, "           vertices:", ridge->vertices);
   if (ridge->top && ridge->bottom)
     qh_fprintf(qh, fp, 9226, "           between f%d and f%d\n",
             ridge->top->id, ridge->bottom->id);
 } /* printridge */
 
 /*---------------------------------
 
   qh_printspheres(qh, fp, vertices, radius )
     prints 3-d vertices as OFF spheres
 
   notes:
     inflated octahedron from Stuart Levy earth/mksphere2
 */
 void qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius) {
   vertexT *vertex, **vertexp;
 
   qh->printoutnum++;
   qh_fprintf(qh, fp, 9227, "{appearance {-edge -normal normscale 0} {\n\
 INST geom {define vsphere OFF\n\
 18 32 48\n\
 \n\
 0 0 1\n\
 1 0 0\n\
 0 1 0\n\
 -1 0 0\n\
 0 -1 0\n\
 0 0 -1\n\
 0.707107 0 0.707107\n\
 0 -0.707107 0.707107\n\
 0.707107 -0.707107 0\n\
 -0.707107 0 0.707107\n\
 -0.707107 -0.707107 0\n\
 0 0.707107 0.707107\n\
 -0.707107 0.707107 0\n\
 0.707107 0.707107 0\n\
 0.707107 0 -0.707107\n\
 0 0.707107 -0.707107\n\
 -0.707107 0 -0.707107\n\
 0 -0.707107 -0.707107\n\
 \n\
 3 0 6 11\n\
 3 0 7 6 \n\
 3 0 9 7 \n\
 3 0 11 9\n\
 3 1 6 8 \n\
 3 1 8 14\n\
 3 1 13 6\n\
 3 1 14 13\n\
 3 2 11 13\n\
 3 2 12 11\n\
 3 2 13 15\n\
 3 2 15 12\n\
 3 3 9 12\n\
 3 3 10 9\n\
 3 3 12 16\n\
 3 3 16 10\n\
 3 4 7 10\n\
 3 4 8 7\n\
 3 4 10 17\n\
 3 4 17 8\n\
 3 5 14 17\n\
 3 5 15 14\n\
 3 5 16 15\n\
 3 5 17 16\n\
 3 6 13 11\n\
 3 7 8 6\n\
 3 9 10 7\n\
 3 11 12 9\n\
 3 14 8 17\n\
 3 15 13 14\n\
 3 16 12 15\n\
 3 17 10 16\n} transforms { TLIST\n");
   FOREACHvertex_(vertices) {
     qh_fprintf(qh, fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
       radius, vertex->id, radius, radius);
     qh_printpoint3(qh, fp, vertex->point);
     qh_fprintf(qh, fp, 9229, "1\n");
   }
   qh_fprintf(qh, fp, 9230, "}}}\n");
 } /* printspheres */
 
 
 /*----------------------------------------------
 -printsummary-
                 see libqhull_r.c
 */
 
 /*---------------------------------
 
   qh_printvdiagram(qh, fp, format, facetlist, facets, printall )
     print voronoi diagram
       # of pairs of input sites
       #indices site1 site2 vertex1 ...
 
     sites indexed by input point id
       point 0 is the first input point
     vertices indexed by 'o' and 'p' order
       vertex 0 is the 'vertex-at-infinity'
       vertex 1 is the first Voronoi vertex
 
   see:
     qh_printvoronoi()
     qh_eachvoronoi_all()
 
   notes:
     if all facets are upperdelaunay,
       prints upper hull (furthest-site Voronoi diagram)
 */
 void qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   setT *vertices;
   int totcount, numcenters;
   boolT isLower;
   qh_RIDGE innerouter= qh_RIDGEall;
   printvridgeT printvridge= NULL;
 
   if (format == qh_PRINTvertices) {
     innerouter= qh_RIDGEall;
     printvridge= qh_printvridge;
   }else if (format == qh_PRINTinner) {
     innerouter= qh_RIDGEinner;
     printvridge= qh_printvnorm;
   }else if (format == qh_PRINTouter) {
     innerouter= qh_RIDGEouter;
     printvridge= qh_printvnorm;
   }else {
     qh_fprintf(qh, qh->ferr, 6219, "Qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);
   totcount= qh_printvdiagram2(qh, NULL, NULL, vertices, innerouter, False);
   qh_fprintf(qh, fp, 9231, "%d\n", totcount);
   totcount= qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, True /* inorder*/);
   qh_settempfree(qh, &vertices);
 #if 0  /* for testing qh_eachvoronoi_all */
   qh_fprintf(qh, fp, 9232, "\n");
   totcount= qh_eachvoronoi_all(qh, fp, printvridge, qh->UPPERdelaunay, innerouter, True /* inorder*/);
   qh_fprintf(qh, fp, 9233, "%d\n", totcount);
 #endif
 } /* printvdiagram */
 
 /*---------------------------------
 
   qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, inorder )
     visit all pairs of input sites (vertices) for selected Voronoi vertices
     vertices may include NULLs
 
   innerouter:
     qh_RIDGEall   print inner ridges(bounded) and outer ridges(unbounded)
     qh_RIDGEinner print only inner ridges
     qh_RIDGEouter print only outer ridges
 
   inorder:
     print 3-d Voronoi vertices in order
 
   assumes:
     qh_markvoronoi marked facet->visitid for Voronoi vertices
     all facet->seen= False
     all facet->seen2= True
 
   returns:
     total number of Voronoi ridges
     if printvridge,
       calls printvridge( fp, vertex, vertexA, centers) for each ridge
       [see qh_eachvoronoi()]
 
   see:
     qh_eachvoronoi_all()
 */
 int qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
   int totcount= 0;
   int vertex_i, vertex_n;
   vertexT *vertex;
 
   FORALLvertices
     vertex->seen= False;
   FOREACHvertex_i_(qh, vertices) {
     if (vertex) {
       if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)
         continue;
       totcount += qh_eachvoronoi(qh, fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
     }
   }
   return totcount;
 } /* printvdiagram2 */
 
 /*---------------------------------
 
   qh_printvertex(qh, fp, vertex )
     prints the information in a vertex
     Duplicated as operator<< [QhullVertex.cpp]
 */
 void qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex) {
   pointT *point;
   int k, count= 0;
   facetT *neighbor, **neighborp;
   realT r; /*bug fix*/
 
   if (!vertex) {
     qh_fprintf(qh, fp, 9234, "  NULLvertex\n");
     return;
   }
   qh_fprintf(qh, fp, 9235, "- p%d(v%d):", qh_pointid(qh, vertex->point), vertex->id);
   point= vertex->point;
   if (point) {
     for (k=qh->hull_dim; k--; ) {
       r= *point++;
       qh_fprintf(qh, fp, 9236, " %5.2g", r);
     }
   }
   if (vertex->deleted)
     qh_fprintf(qh, fp, 9237, " deleted");
   if (vertex->delridge)
     qh_fprintf(qh, fp, 9238, " ridgedeleted");
   qh_fprintf(qh, fp, 9239, "\n");
   if (vertex->neighbors) {
     qh_fprintf(qh, fp, 9240, "  neighbors:");
     FOREACHneighbor_(vertex) {
       if (++count % 100 == 0)
         qh_fprintf(qh, fp, 9241, "\n     ");
       qh_fprintf(qh, fp, 9242, " f%d", neighbor->id);
     }
     qh_fprintf(qh, fp, 9243, "\n");
   }
 } /* printvertex */
 
 
 /*---------------------------------
 
   qh_printvertexlist(qh, fp, string, facetlist, facets, printall )
     prints vertices used by a facetlist or facet set
     tests qh_skipfacet() if !printall
 */
 void qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,
                          setT *facets, boolT printall) {
   vertexT *vertex, **vertexp;
   setT *vertices;
 
   vertices= qh_facetvertices(qh, facetlist, facets, printall);
   qh_fprintf(qh, fp, 9244, "%s", string);
   FOREACHvertex_(vertices)
     qh_printvertex(qh, fp, vertex);
   qh_settempfree(qh, &vertices);
 } /* printvertexlist */
 
 
 /*---------------------------------
 
   qh_printvertices(qh, fp, string, vertices )
     prints vertices in a set
     duplicated as printVertexSet [QhullVertex.cpp]
 */
 void qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices) {
   vertexT *vertex, **vertexp;
 
   qh_fprintf(qh, fp, 9245, "%s", string);
   FOREACHvertex_(vertices)
     qh_fprintf(qh, fp, 9246, " p%d(v%d)", qh_pointid(qh, vertex->point), vertex->id);
   qh_fprintf(qh, fp, 9247, "\n");
 } /* printvertices */
 
 /*---------------------------------
 
   qh_printvneighbors(qh, fp, facetlist, facets, printall )
     print vertex neighbors of vertices in facetlist and facets ('FN')
 
   notes:
     qh_countfacets clears facet->visitid for non-printed facets
 
   design:
     collect facet count and related statistics
     if necessary, build neighbor sets for each vertex
     collect vertices in facetlist and facets
     build a point array for point->vertex and point->coplanar facet
     for each point
       list vertex neighbors or coplanar facet
 */
 void qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
   int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
   setT *vertices, *vertex_points, *coplanar_points;
   int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
   vertexT *vertex, **vertexp;
   int vertex_i, vertex_n;
   facetT *facet, **facetp, *neighbor, **neighborp;
   pointT *point, **pointp;
 
   qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
       &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
   qh_fprintf(qh, fp, 9248, "%d\n", numpoints);
   qh_vertexneighbors(qh);
   vertices= qh_facetvertices(qh, facetlist, facets, printall);
   vertex_points= qh_settemp(qh, numpoints);
   coplanar_points= qh_settemp(qh, numpoints);
   qh_setzero(qh, vertex_points, 0, numpoints);
   qh_setzero(qh, coplanar_points, 0, numpoints);
   FOREACHvertex_(vertices)
     qh_point_add(qh, vertex_points, vertex->point, vertex);
   FORALLfacet_(facetlist) {
     FOREACHpoint_(facet->coplanarset)
       qh_point_add(qh, coplanar_points, point, facet);
   }
   FOREACHfacet_(facets) {
     FOREACHpoint_(facet->coplanarset)
       qh_point_add(qh, coplanar_points, point, facet);
   }
   FOREACHvertex_i_(qh, vertex_points) {
     if (vertex) {
       numneighbors= qh_setsize(qh, vertex->neighbors);
       qh_fprintf(qh, fp, 9249, "%d", numneighbors);
       if (qh->hull_dim == 3)
         qh_order_vertexneighbors(qh, vertex);
       else if (qh->hull_dim >= 4)
         qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,
              sizeof(facetT *), qh_compare_facetvisit);
       FOREACHneighbor_(vertex)
         qh_fprintf(qh, fp, 9250, " %d",
                  neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);
       qh_fprintf(qh, fp, 9251, "\n");
     }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
       qh_fprintf(qh, fp, 9252, "1 %d\n",
                   facet->visitid ? facet->visitid - 1 : 0 - facet->id);
     else
       qh_fprintf(qh, fp, 9253, "0\n");
   }
   qh_settempfree(qh, &coplanar_points);
   qh_settempfree(qh, &vertex_points);
   qh_settempfree(qh, &vertices);
 } /* printvneighbors */
 
 /*---------------------------------
 
   qh_printvoronoi(qh, fp, format, facetlist, facets, printall )
     print voronoi diagram in 'o' or 'G' format
     for 'o' format
       prints voronoi centers for each facet and for infinity
       for each vertex, lists ids of printed facets or infinity
       assumes facetlist and facets are disjoint
     for 'G' format
       prints an OFF object
       adds a 0 coordinate to center
       prints infinity but does not list in vertices
 
   see:
     qh_printvdiagram()
 
   notes:
     if 'o',
       prints a line for each point except "at-infinity"
     if all facets are upperdelaunay,
       reverses lower and upper hull
 */
 void qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
   int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
   facetT *facet, **facetp, *neighbor, **neighborp;
   setT *vertices;
   vertexT *vertex;
   boolT isLower;
   unsigned int numfacets= (unsigned int) qh->num_facets;
 
   vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);
   FOREACHvertex_i_(qh, vertices) {
     if (vertex) {
       numvertices++;
       numneighbors = numinf = 0;
       FOREACHneighbor_(vertex) {
         if (neighbor->visitid == 0)
           numinf= 1;
         else if (neighbor->visitid < numfacets)
           numneighbors++;
       }
       if (numinf && !numneighbors) {
         SETelem_(vertices, vertex_i)= NULL;
         numvertices--;
       }
     }
   }
   if (format == qh_PRINTgeom)
     qh_fprintf(qh, fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
                 numcenters, numvertices);
   else
     qh_fprintf(qh, fp, 9255, "%d\n%d %d 1\n", qh->hull_dim-1, numcenters, qh_setsize(qh, vertices));
   if (format == qh_PRINTgeom) {
     for (k=qh->hull_dim-1; k--; )
       qh_fprintf(qh, fp, 9256, qh_REAL_1, 0.0);
     qh_fprintf(qh, fp, 9257, " 0 # infinity not used\n");
   }else {
     for (k=qh->hull_dim-1; k--; )
       qh_fprintf(qh, fp, 9258, qh_REAL_1, qh_INFINITE);
     qh_fprintf(qh, fp, 9259, "\n");
   }
   FORALLfacet_(facetlist) {
     if (facet->visitid && facet->visitid < numfacets) {
       if (format == qh_PRINTgeom)
         qh_fprintf(qh, fp, 9260, "# %d f%d\n", vid++, facet->id);
       qh_printcenter(qh, fp, format, NULL, facet);
     }
   }
   FOREACHfacet_(facets) {
     if (facet->visitid && facet->visitid < numfacets) {
       if (format == qh_PRINTgeom)
         qh_fprintf(qh, fp, 9261, "# %d f%d\n", vid++, facet->id);
       qh_printcenter(qh, fp, format, NULL, facet);
     }
   }
   FOREACHvertex_i_(qh, vertices) {
     numneighbors= 0;
     numinf=0;
     if (vertex) {
       if (qh->hull_dim == 3)
         qh_order_vertexneighbors(qh, vertex);
       else if (qh->hull_dim >= 4)
         qsort(SETaddr_(vertex->neighbors, facetT),
              (size_t)qh_setsize(qh, vertex->neighbors),
              sizeof(facetT *), qh_compare_facetvisit);
       FOREACHneighbor_(vertex) {
         if (neighbor->visitid == 0)
           numinf= 1;
         else if (neighbor->visitid < numfacets)
           numneighbors++;
       }
     }
     if (format == qh_PRINTgeom) {
       if (vertex) {
         qh_fprintf(qh, fp, 9262, "%d", numneighbors);
         FOREACHneighbor_(vertex) {
           if (neighbor->visitid && neighbor->visitid < numfacets)
             qh_fprintf(qh, fp, 9263, " %d", neighbor->visitid);
         }
         qh_fprintf(qh, fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);
       }else
         qh_fprintf(qh, fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);
     }else {
       if (numinf)
         numneighbors++;
       qh_fprintf(qh, fp, 9266, "%d", numneighbors);
       if (vertex) {
         FOREACHneighbor_(vertex) {
           if (neighbor->visitid == 0) {
             if (numinf) {
               numinf= 0;
               qh_fprintf(qh, fp, 9267, " %d", neighbor->visitid);
             }
           }else if (neighbor->visitid < numfacets)
             qh_fprintf(qh, fp, 9268, " %d", neighbor->visitid);
         }
       }
       qh_fprintf(qh, fp, 9269, "\n");
     }
   }
   if (format == qh_PRINTgeom)
     qh_fprintf(qh, fp, 9270, "}\n");
   qh_settempfree(qh, &vertices);
 } /* printvoronoi */
 
 /*---------------------------------
 
   qh_printvnorm(qh, fp, vertex, vertexA, centers, unbounded )
     print one separating plane of the Voronoi diagram for a pair of input sites
     unbounded==True if centers includes vertex-at-infinity
 
   assumes:
     qh_ASvoronoi and qh_vertexneighbors() already set
 
   note:
     parameter unbounded is UNUSED by this callback
 
   see:
     qh_printvdiagram()
     qh_eachvoronoi()
 */
 void qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
   pointT *normal;
   realT offset;
   int k;
   QHULL_UNUSED(unbounded);
 
   normal= qh_detvnorm(qh, vertex, vertexA, centers, &offset);
   qh_fprintf(qh, fp, 9271, "%d %d %d ",
       2+qh->hull_dim, qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));
   for (k=0; k< qh->hull_dim-1; k++)
     qh_fprintf(qh, fp, 9272, qh_REAL_1, normal[k]);
   qh_fprintf(qh, fp, 9273, qh_REAL_1, offset);
   qh_fprintf(qh, fp, 9274, "\n");
 } /* printvnorm */
 
 /*---------------------------------
 
   qh_printvridge(qh, fp, vertex, vertexA, centers, unbounded )
     print one ridge of the Voronoi diagram for a pair of input sites
     unbounded==True if centers includes vertex-at-infinity
 
   see:
     qh_printvdiagram()
 
   notes:
     the user may use a different function
     parameter unbounded is UNUSED
 */
 void qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
   facetT *facet, **facetp;
   QHULL_UNUSED(unbounded);
 
   qh_fprintf(qh, fp, 9275, "%d %d %d", qh_setsize(qh, centers)+2,
        qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));
   FOREACHfacet_(centers)
     qh_fprintf(qh, fp, 9276, " %d", facet->visitid);
   qh_fprintf(qh, fp, 9277, "\n");
 } /* printvridge */
 
 /*---------------------------------
 
   qh_projectdim3(qh, source, destination )
     project 2-d 3-d or 4-d point to a 3-d point
     uses qh.DROPdim and qh.hull_dim
     source and destination may be the same
 
   notes:
     allocate 4 elements to destination just in case
 */
 void qh_projectdim3(qhT *qh, pointT *source, pointT *destination) {
   int i,k;
 
   for (k=0, i=0; k < qh->hull_dim; k++) {
     if (qh->hull_dim == 4) {
       if (k != qh->DROPdim)
         destination[i++]= source[k];
     }else if (k == qh->DROPdim)
       destination[i++]= 0;
     else
       destination[i++]= source[k];
   }
   while (i < 3)
     destination[i++]= 0.0;
 } /* projectdim3 */
 
 /*---------------------------------
 
   qh_readfeasible(qh, dim, curline )
     read feasible point from current line and qh.fin
 
   returns:
     number of lines read from qh.fin
     sets qh.FEASIBLEpoint with malloc'd coordinates
 
   notes:
     checks for qh.HALFspace
     assumes dim > 1
 
   see:
     qh_setfeasible
 */
 int qh_readfeasible(qhT *qh, int dim, const char *curline) {
   boolT isfirst= True;
   int linecount= 0, tokcount= 0;
   const char *s;
   char *t, firstline[qh_MAXfirst+1];
   coordT *coords, value;
 
   if (!qh->HALFspace) {
     qh_fprintf(qh, qh->ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (qh->feasible_string)
     qh_fprintf(qh, qh->ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
   if (!(qh->feasible_point= (coordT*)qh_malloc(dim* sizeof(coordT)))) {
     qh_fprintf(qh, qh->ferr, 6071, "qhull error: insufficient memory for feasible point\n");
     qh_errexit(qh, qh_ERRmem, NULL, NULL);
   }
   coords= qh->feasible_point;
   while ((s= (isfirst ?  curline : fgets(firstline, qh_MAXfirst, qh->fin)))) {
     if (isfirst)
       isfirst= False;
     else
       linecount++;
     while (*s) {
       while (isspace(*s))
         s++;
       value= qh_strtod(s, &t);
       if (s == t)
         break;
       s= t;
       *(coords++)= value;
       if (++tokcount == dim) {
         while (isspace(*s))
           s++;
         qh_strtod(s, &t);
         if (s != t) {
           qh_fprintf(qh, qh->ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
                s);
           qh_errexit(qh, qh_ERRinput, NULL, NULL);
         }
         return linecount;
       }
     }
   }
   qh_fprintf(qh, qh->ferr, 6073, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
            tokcount, dim);
   qh_errexit(qh, qh_ERRinput, NULL, NULL);
   return 0;
 } /* readfeasible */
 
 /*---------------------------------
 
   qh_readpoints(qh, numpoints, dimension, ismalloc )
     read points from qh.fin into qh.first_point, qh.num_points
     qh.fin is lines of coordinates, one per vertex, first line number of points
     if 'rbox D4',
       gives message
     if qh.ATinfinity,
       adds point-at-infinity for Delaunay triangulations
 
   returns:
     number of points, array of point coordinates, dimension, ismalloc True
     if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
         and clears qh.PROJECTdelaunay
     if qh.HALFspace, reads optional feasible point, reads halfspaces,
         converts to dual.
 
   for feasible point in "cdd format" in 3-d:
     3 1
     coordinates
     comments
     begin
     n 4 real/integer
     ...
     end
 
   notes:
     dimension will change in qh_initqhull_globals if qh.PROJECTinput
     uses malloc() since qh_mem not initialized
     FIXUP QH11012: qh_readpoints needs rewriting, too long
 */
 coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc) {
   coordT *points, *coords, *infinity= NULL;
   realT paraboloid, maxboloid= -REALmax, value;
   realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
   char *s= 0, *t, firstline[qh_MAXfirst+1];
   int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
   int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
   int tokcount= 0, linecount=0, maxcount, coordcount=0;
   boolT islong, isfirst= True, wasbegin= False;
   boolT isdelaunay= qh->DELAUNAY && !qh->PROJECTinput;
 
   if (qh->CDDinput) {
     while ((s= fgets(firstline, qh_MAXfirst, qh->fin))) {
       linecount++;
       if (qh->HALFspace && linecount == 1 && isdigit(*s)) {
         dimfeasible= qh_strtol(s, &s);
         while (isspace(*s))
           s++;
         if (qh_strtol(s, &s) == 1)
           linecount += qh_readfeasible(qh, dimfeasible, s);
         else
           dimfeasible= 0;
       }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))
         break;
       else if (!*qh->rbox_command)
         strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
     }
     if (!s) {
       qh_fprintf(qh, qh->ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
   }
   while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh->fin))) {
     linecount++;
     if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))
       wasbegin= True;
     while (*s) {
       while (isspace(*s))
         s++;
       if (!*s)
         break;
       if (!isdigit(*s)) {
         if (!*qh->rbox_command) {
           strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
           firsttext= linecount;
         }
         break;
       }
       if (!diminput)
         diminput= qh_strtol(s, &s);
       else {
         numinput= qh_strtol(s, &s);
         if (numinput == 1 && diminput >= 2 && qh->HALFspace && !qh->CDDinput) {
           linecount += qh_readfeasible(qh, diminput, s); /* checks if ok */
           dimfeasible= diminput;
           diminput= numinput= 0;
         }else
           break;
       }
     }
   }
   if (!s) {
     qh_fprintf(qh, qh->ferr, 6075, "qhull input error: short input file.  Did not find dimension and number of points\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (diminput > numinput) {
     tempi= diminput;    /* exchange dim and n, e.g., for cdd input format */
     diminput= numinput;
     numinput= tempi;
   }
   if (diminput < 2) {
     qh_fprintf(qh, qh->ferr, 6220,"qhull input error: dimension %d(first number) should be at least 2\n",
             diminput);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (isdelaunay) {
     qh->PROJECTdelaunay= False;
     if (qh->CDDinput)
       *dimension= diminput;
     else
       *dimension= diminput+1;
     *numpoints= numinput;
     if (qh->ATinfinity)
       (*numpoints)++;
   }else if (qh->HALFspace) {
     *dimension= diminput - 1;
     *numpoints= numinput;
     if (diminput < 3) {
       qh_fprintf(qh, qh->ferr, 6221,"qhull input error: dimension %d(first number, includes offset) should be at least 3 for halfspaces\n",
             diminput);
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     if (dimfeasible) {
       if (dimfeasible != *dimension) {
         qh_fprintf(qh, qh->ferr, 6222,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
           dimfeasible, diminput);
         qh_errexit(qh, qh_ERRinput, NULL, NULL);
       }
     }else
       qh_setfeasible(qh, *dimension);
   }else {
     if (qh->CDDinput)
       *dimension= diminput-1;
     else
       *dimension= diminput;
     *numpoints= numinput;
   }
   qh->normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
   if (qh->HALFspace) {
     qh->half_space= coordp= (coordT*)qh_malloc(qh->normal_size + sizeof(coordT));
     if (qh->CDDinput) {
       offsetp= qh->half_space;
       normalp= offsetp + 1;
     }else {
       normalp= qh->half_space;
       offsetp= normalp + *dimension;
     }
   }
   qh->maxline= diminput * (qh_REALdigits + 5);
   maximize_(qh->maxline, 500);
   qh->line= (char*)qh_malloc((qh->maxline+1) * sizeof(char));
   *ismalloc= True;  /* use malloc since memory not setup */
   coords= points= qh->temp_malloc=
         (coordT*)qh_malloc((*numpoints)*(*dimension)*sizeof(coordT));
   if (!coords || !qh->line || (qh->HALFspace && !qh->half_space)) {
     qh_fprintf(qh, qh->ferr, 6076, "qhull error: insufficient memory to read %d points\n",
             numinput);
     qh_errexit(qh, qh_ERRmem, NULL, NULL);
   }
   if (isdelaunay && qh->ATinfinity) {
     infinity= points + numinput * (*dimension);
     for (k= (*dimension) - 1; k--; )
       infinity[k]= 0.0;
   }
   maxcount= numinput * diminput;
   paraboloid= 0.0;
   while ((s= (isfirst ?  s : fgets(qh->line, qh->maxline, qh->fin)))) {
     if (!isfirst) {
       linecount++;
       if (*s == 'e' || *s == 'E') {
         if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {
           if (qh->CDDinput )
             break;
           else if (wasbegin)
             qh_fprintf(qh, qh->ferr, 7058, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
         }
       }
     }
     islong= False;
     while (*s) {
       while (isspace(*s))
         s++;
       value= qh_strtod(s, &t);
       if (s == t) {
         if (!*qh->rbox_command)
          strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
         if (*s && !firsttext)
           firsttext= linecount;
         if (!islong && !firstshort && coordcount)
           firstshort= linecount;
         break;
       }
       if (!firstpoint)
         firstpoint= linecount;
       s= t;
       if (++tokcount > maxcount)
         continue;
       if (qh->HALFspace) {
         if (qh->CDDinput)
           *(coordp++)= -value; /* both coefficients and offset */
         else
           *(coordp++)= value;
       }else {
         *(coords++)= value;
         if (qh->CDDinput && !coordcount) {
           if (value != 1.0) {
             qh_fprintf(qh, qh->ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
                    linecount);
             qh_errexit(qh, qh_ERRinput, NULL, NULL);
           }
           coords--;
         }else if (isdelaunay) {
           paraboloid += value * value;
           if (qh->ATinfinity) {
             if (qh->CDDinput)
               infinity[coordcount-1] += value;
             else
               infinity[coordcount] += value;
           }
         }
       }
       if (++coordcount == diminput) {
         coordcount= 0;
         if (isdelaunay) {
           *(coords++)= paraboloid;
           maximize_(maxboloid, paraboloid);
           paraboloid= 0.0;
         }else if (qh->HALFspace) {
           if (!qh_sethalfspace(qh, *dimension, coords, &coords, normalp, offsetp, qh->feasible_point)) {
             qh_fprintf(qh, qh->ferr, 8048, "The halfspace was on line %d\n", linecount);
             if (wasbegin)
               qh_fprintf(qh, qh->ferr, 8049, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
             qh_errexit(qh, qh_ERRinput, NULL, NULL);
           }
           coordp= qh->half_space;
         }
         while (isspace(*s))
           s++;
         if (*s) {
           islong= True;
           if (!firstlong)
             firstlong= linecount;
         }
       }
     }
     if (!islong && !firstshort && coordcount)
       firstshort= linecount;
     if (!isfirst && s - qh->line >= qh->maxline) {
       qh_fprintf(qh, qh->ferr, 6078, "qhull input error: line %d contained more than %d characters\n",
               linecount, (int) (s - qh->line));   /* WARN64 */
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     isfirst= False;
   }
   if (tokcount != maxcount) {
     newnum= fmin_(numinput, tokcount/diminput);
     qh_fprintf(qh, qh->ferr, 7073,"\
 qhull warning: instead of %d %d-dimensional points, input contains\n\
 %d points and %d extra coordinates.  Line %d is the first\npoint",
        numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
     if (firsttext)
       qh_fprintf(qh, qh->ferr, 8051, ", line %d is the first comment", firsttext);
     if (firstshort)
       qh_fprintf(qh, qh->ferr, 8052, ", line %d is the first short\nline", firstshort);
     if (firstlong)
       qh_fprintf(qh, qh->ferr, 8053, ", line %d is the first long line", firstlong);
     qh_fprintf(qh, qh->ferr, 8054, ".  Continue with %d points.\n", newnum);
     numinput= newnum;
     if (isdelaunay && qh->ATinfinity) {
       for (k= tokcount % diminput; k--; )
         infinity[k] -= *(--coords);
       *numpoints= newnum+1;
     }else {
       coords -= tokcount % diminput;
       *numpoints= newnum;
     }
   }
   if (isdelaunay && qh->ATinfinity) {
     for (k= (*dimension) -1; k--; )
       infinity[k] /= numinput;
     if (coords == infinity)
       coords += (*dimension) -1;
     else {
       for (k=0; k < (*dimension) -1; k++)
         *(coords++)= infinity[k];
     }
     *(coords++)= maxboloid * 1.1;
   }
   if (qh->rbox_command[0]) {
     qh->rbox_command[strlen(qh->rbox_command)-1]= '\0';
     if (!strcmp(qh->rbox_command, "./rbox D4"))
       qh_fprintf(qh, qh->ferr, 8055, "\n\
 This is the qhull test case.  If any errors or core dumps occur,\n\
 recompile qhull with 'make new'.  If errors still occur, there is\n\
 an incompatibility.  You should try a different compiler.  You can also\n\
 change the choices in user.h.  If you discover the source of the problem,\n\
 please send mail to qhull_bug@qhull.org.\n\
 \n\
 Type 'qhull' for a short list of options.\n");
   }
   qh_free(qh->line);
   qh->line= NULL;
   if (qh->half_space) {
     qh_free(qh->half_space);
     qh->half_space= NULL;
   }
   qh->temp_malloc= NULL;
   trace1((qh, qh->ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",
           numinput, diminput));
   return(points);
 } /* readpoints */
 
 
 /*---------------------------------
 
   qh_setfeasible(qh, dim )
     set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
 
   notes:
     "n,n,n" already checked by qh_initflags()
     see qh_readfeasible()
 */
 void qh_setfeasible(qhT *qh, int dim) {
   int tokcount= 0;
   char *s;
   coordT *coords, value;
 
   if (!(s= qh->feasible_string)) {
     qh_fprintf(qh, qh->ferr, 6223, "\
 qhull input error: halfspace intersection needs a feasible point.\n\
 Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (!(qh->feasible_point= (pointT*)qh_malloc(dim * sizeof(coordT)))) {
     qh_fprintf(qh, qh->ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");
     qh_errexit(qh, qh_ERRmem, NULL, NULL);
   }
   coords= qh->feasible_point;
   while (*s) {
     value= qh_strtod(s, &s);
     if (++tokcount > dim) {
       qh_fprintf(qh, qh->ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
           qh->feasible_string, dim);
       break;
     }
     *(coords++)= value;
     if (*s)
       s++;
   }
   while (++tokcount <= dim)
     *(coords++)= 0.0;
 } /* setfeasible */
 
 /*---------------------------------
 
   qh_skipfacet(qh, facet )
     returns 'True' if this facet is not to be printed
 
   notes:
     based on the user provided slice thresholds and 'good' specifications
 */
 boolT qh_skipfacet(qhT *qh, facetT *facet) {
   facetT *neighbor, **neighborp;
 
   if (qh->PRINTneighbors) {
     if (facet->good)
       return !qh->PRINTgood;
     FOREACHneighbor_(facet) {
       if (neighbor->good)
         return False;
     }
     return True;
   }else if (qh->PRINTgood)
     return !facet->good;
   else if (!facet->normal)
     return True;
   return(!qh_inthresholds(qh, facet->normal, NULL));
 } /* skipfacet */
 
 /*---------------------------------
 
   qh_skipfilename(qh, string )
     returns pointer to character after filename
 
   notes:
     skips leading spaces
     ends with spacing or eol
     if starts with ' or " ends with the same, skipping \' or \"
     For qhull, qh_argv_to_command() only uses double quotes
 */
 char *qh_skipfilename(qhT *qh, char *filename) {
   char *s= filename;  /* non-const due to return */
   char c;
 
   while (*s && isspace(*s))
     s++;
   c= *s++;
   if (c == '\0') {
     qh_fprintf(qh, qh->ferr, 6204, "qhull input error: filename expected, none found.\n");
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   if (c == '\'' || c == '"') {
     while (*s !=c || s[-1] == '\\') {
       if (!*s) {
         qh_fprintf(qh, qh->ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);
         qh_errexit(qh, qh_ERRinput, NULL, NULL);
       }
       s++;
     }
     s++;
   }
   else while (*s && !isspace(*s))
       s++;
   return s;
 } /* skipfilename */
 
diff --git a/src/libqhullr/io_r.h b/src/libqhullr/io_r.h
index 1bba4a6..e3dfe30 100644
--- a/src/libqhullr/io_r.h
+++ b/src/libqhullr/io_r.h
@@ -1,159 +1,159 @@
 /*
  ---------------------------------
 
    io_r.h
    declarations of Input/Output functions
 
    see README, libqhull_r.h and io_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/io_r.h#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/io_r.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFio
 #define qhDEFio 1
 
 #include "libqhull_r.h"
 
 /*============ constants and flags ==================*/
 
 /*----------------------------------
 
   qh_MAXfirst
     maximum length of first two lines of stdin
 */
 #define qh_MAXfirst  200
 
 /*----------------------------------
 
   qh_MINradius
     min radius for Gp and Gv, fraction of maxcoord
 */
 #define qh_MINradius 0.02
 
 /*----------------------------------
 
   qh_GEOMepsilon
     adjust outer planes for 'lines closer' and geomview roundoff.
     This prevents bleed through.
 */
 #define qh_GEOMepsilon 2e-3
 
 /*----------------------------------
 
   qh_WHITESPACE
     possible values of white space
 */
 #define qh_WHITESPACE " \n\t\v\r\f"
 
 
 /*----------------------------------
 
   qh_RIDGE
     to select which ridges to print in qh_eachvoronoi
 */
 typedef enum
 {
     qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
 }
 qh_RIDGE;
 
 /*----------------------------------
 
   printvridgeT
     prints results of qh_printvdiagram
 
   see:
     qh_printvridge for an example
 */
 typedef void (*printvridgeT)(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
 
 /*============== -prototypes in alphabetical order =========*/
 
 void    qh_dfacet(qhT *qh, unsigned id);
 void    qh_dvertex(qhT *qh, unsigned id);
 int     qh_compare_facetarea(const void *p1, const void *p2);
 int     qh_compare_facetmerge(const void *p1, const void *p2);
 int     qh_compare_facetvisit(const void *p1, const void *p2);
 /* int  qh_compare_vertexpoint(const void *p1, const void *p2); Not useable since it depends on qh */
 void    qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length);
 void    qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,
               int *numfacetsp, int *numsimplicialp, int *totneighborsp,
               int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
 pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
 setT   *qh_detvridge(qhT *qh, vertexT *vertex);
 setT   *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex);
 int     qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
 int     qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder);
 void    qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist);
 setT   *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets);
 void    qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
 void    qh_markkeep(qhT *qh, facetT *facetlist);
 setT   *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp);
 void    qh_order_vertexneighbors(qhT *qh, vertexT *vertex);
 void    qh_prepare_output(qhT *qh);
 void    qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall);
 void    qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet);
 void    qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius);
 void    qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *num, boolT printall);
 void    qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printfacet(qhT *qh, FILE *fp, facetT *facet);
 void    qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
 void    qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,
                                facetT *facet, realT offset, realT color[3]);
 void    qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
 void    qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
 void    qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format);
 void    qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
 void    qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format);
 void    qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format);
 void    qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet);
 void    qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet);
 void    qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,
                    setT *vertices, realT color[3]);
 void    qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
 void    qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
 void    qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point);
 void    qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id);
 void    qh_printpoint3(qhT *qh, FILE *fp, pointT *point);
 void    qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
 void    qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
 void    qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge);
 void    qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius);
 void    qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 int     qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
 void    qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex);
 void    qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,
                          setT *facets, boolT printall);
 void    qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices);
 void    qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall);
 void    qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
 void    qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
 void    qh_produce_output(qhT *qh);
 void    qh_produce_output2(qhT *qh);
 void    qh_projectdim3(qhT *qh, pointT *source, pointT *destination);
 int     qh_readfeasible(qhT *qh, int dim, const char *curline);
 coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc);
 void    qh_setfeasible(qhT *qh, int dim);
 boolT   qh_skipfacet(qhT *qh, facetT *facet);
 char   *qh_skipfilename(qhT *qh, char *filename);
 
 #endif /* qhDEFio */
diff --git a/src/libqhullr/libqhull_r.c b/src/libqhullr/libqhull_r.c
index 51c70b8..44602ea 100644
--- a/src/libqhullr/libqhull_r.c
+++ b/src/libqhullr/libqhull_r.c
@@ -1,1403 +1,1403 @@
 /*
  ---------------------------------
 
    libqhull_r.c
    Quickhull algorithm for convex hulls
 
    qhull() and top-level routines
 
    see qh-qhull.htm, libqhull.h, unix_r.c
 
    see qhull_ra.h for internal functions
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/libqhull_r.c#8 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/libqhull_r.c#9 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_ra.h"
 
 /*============= functions in alphabetic order after qhull() =======*/
 
 /*---------------------------------
 
   qh_qhull(qh)
     compute DIM3 convex hull of qh.num_points starting at qh.first_point
     qh->contains all global options and variables
 
   returns:
     returns polyhedron
       qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,
 
     returns global variables
       qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex
 
     returns precision constants
       qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge
 
   notes:
     unless needed for output
       qh.max_vertex and qh.min_vertex are max/min due to merges
 
   see:
     to add individual points to either qh.num_points
       use qh_addpoint()
 
     if qh.GETarea
       qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()
 
   design:
     record starting time
     initialize hull and partition points
     build convex hull
     unless early termination
       update facet->maxoutside for vertices, coplanar, and near-inside points
     error if temporary sets exist
     record end time
 */
 
 void qh_qhull(qhT *qh) {
   int numoutside;
 
   qh->hulltime= qh_CPUclock;
   if (qh->RERUN || qh->JOGGLEmax < REALmax/2)
     qh_build_withrestart(qh);
   else {
     qh_initbuild(qh);
     qh_buildhull(qh);
   }
   if (!qh->STOPpoint && !qh->STOPcone) {
     if (qh->ZEROall_ok && !qh->TESTvneighbors && qh->MERGEexact)
       qh_checkzero(qh, qh_ALL);
     if (qh->ZEROall_ok && !qh->TESTvneighbors && !qh->WAScoplanar) {
       trace2((qh, qh->ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
       qh->DOcheckmax= False;
     }else {
       if (qh->MERGEexact || (qh->hull_dim > qh_DIMreduceBuild && qh->PREmerge))
         qh_postmerge(qh, "First post-merge", qh->premerge_centrum, qh->premerge_cos,
              (qh->POSTmerge ? False : qh->TESTvneighbors));
       else if (!qh->POSTmerge && qh->TESTvneighbors)
         qh_postmerge(qh, "For testing vertex neighbors", qh->premerge_centrum,
              qh->premerge_cos, True);
       if (qh->POSTmerge)
         qh_postmerge(qh, "For post-merging", qh->postmerge_centrum,
              qh->postmerge_cos, qh->TESTvneighbors);
       if (qh->visible_list == qh->facet_list) { /* i.e., merging done */
         qh->findbestnew= True;
         qh_partitionvisible(qh /*qh.visible_list*/, !qh_ALL, &numoutside);
         qh->findbestnew= False;
         qh_deletevisible(qh /*qh.visible_list*/);
         qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
       }
     }
     if (qh->DOcheckmax){
       if (qh->REPORTfreq) {
         qh_buildtracing(qh, NULL, NULL);
         qh_fprintf(qh, qh->ferr, 8115, "\nTesting all coplanar points.\n");
       }
       qh_check_maxout(qh);
     }
     if (qh->KEEPnearinside && !qh->maxoutdone)
       qh_nearcoplanar(qh);
   }
   if (qh_setsize(qh, qh->qhmem.tempstack) != 0) {
     qh_fprintf(qh, qh->ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d)\n",
              qh_setsize(qh, qh->qhmem.tempstack));
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   qh->hulltime= qh_CPUclock - qh->hulltime;
   qh->QHULLfinished= True;
   trace1((qh, qh->ferr, 1036, "Qhull: algorithm completed\n"));
 } /* qhull */
 
 /*---------------------------------
 
   qh_addpoint(qh, furthest, facet, checkdist )
     add point (usually furthest point) above facet to hull
     if checkdist,
       check that point is above facet.
       if point is not outside of the hull, uses qh_partitioncoplanar()
       assumes that facet is defined by qh_findbestfacet()
     else if facet specified,
       assumes that point is above facet (major damage if below)
     for Delaunay triangulations,
       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
 
   returns:
     returns False if user requested an early termination
      qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
     updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
     clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
     if unknown point, adds a pointer to qh.other_points
       do not deallocate the point's coordinates
 
   notes:
     assumes point is near its best facet and not at a local minimum of a lens
       distributions.  Use qh_findbestfacet to avoid this case.
     uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
 
   see also:
     qh_triangulate() -- triangulate non-simplicial facets
 
   design:
     add point to other_points if needed
     if checkdist
       if point not above facet
         partition coplanar point
         exit
     exit if pre STOPpoint requested
     find horizon and visible facets for point
     make new facets for point to horizon
     make hyperplanes for point
     compute balance statistics
     match neighboring new facets
     update vertex neighbors and delete interior vertices
     exit if STOPcone requested
     merge non-convex new facets
     if merge found, many merges, or 'Qf'
        use qh_findbestnew() instead of qh_findbest()
     partition outside points from visible facets
     delete visible facets
     check polyhedron if requested
     exit if post STOPpoint requested
     reset working lists of facets and vertices
 */
 boolT qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist) {
   int goodvisible, goodhorizon;
   vertexT *vertex;
   facetT *newfacet;
   realT dist, newbalance, pbalance;
   boolT isoutside= False;
   int numpart, numpoints, numnew, firstnew;
 
   qh->maxoutdone= False;
   if (qh_pointid(qh, furthest) == -1)
     qh_setappend(qh, &qh->other_points, furthest);
   if (!facet) {
     qh_fprintf(qh, qh->ferr, 6213, "qhull internal error (qh_addpoint): NULL facet.  Need to call qh_findbestfacet first\n");
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   if (checkdist) {
     facet= qh_findbest(qh, furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
                         &dist, &isoutside, &numpart);
     zzadd_(Zpartition, numpart);
     if (!isoutside) {
       zinc_(Znotmax);  /* last point of outsideset is no longer furthest. */
       facet->notfurthest= True;
       qh_partitioncoplanar(qh, furthest, facet, &dist);
       return True;
     }
   }
   qh_buildtracing(qh, furthest, facet);
   if (qh->STOPpoint < 0 && qh->furthest_id == -qh->STOPpoint-1) {
     facet->notfurthest= True;
     return False;
   }
   qh_findhorizon(qh, furthest, facet, &goodvisible, &goodhorizon);
   if (qh->ONLYgood && !(goodvisible+goodhorizon) && !qh->GOODclosest) {
     zinc_(Znotgood);
     facet->notfurthest= True;
     /* last point of outsideset is no longer furthest.  This is ok
        since all points of the outside are likely to be bad */
     qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
     return True;
   }
   zzinc_(Zprocessed);
   firstnew= qh->facet_id;
   vertex= qh_makenewfacets(qh, furthest /*visible_list, attaches if !ONLYgood */);
   qh_makenewplanes(qh /* newfacet_list */);
   numnew= qh->facet_id - firstnew;
   newbalance= numnew - (realT) (qh->num_facets-qh->num_visible)
                          * qh->hull_dim/qh->num_vertices;
   wadd_(Wnewbalance, newbalance);
   wadd_(Wnewbalance2, newbalance * newbalance);
   if (qh->ONLYgood
   && !qh_findgood(qh, qh->newfacet_list, goodhorizon) && !qh->GOODclosest) {
     FORALLnew_facets
       qh_delfacet(qh, newfacet);
     qh_delvertex(qh, vertex);
     qh_resetlists(qh, True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
     zinc_(Znotgoodnew);
     facet->notfurthest= True;
     return True;
   }
   if (qh->ONLYgood)
     qh_attachnewfacets(qh /*visible_list*/);
   qh_matchnewfacets(qh);
   qh_updatevertices(qh);
   if (qh->STOPcone && qh->furthest_id == qh->STOPcone-1) {
     facet->notfurthest= True;
     return False;  /* visible_list etc. still defined */
   }
   qh->findbestnew= False;
   if (qh->PREmerge || qh->MERGEexact) {
     qh_premerge(qh, vertex, qh->premerge_centrum, qh->premerge_cos);
     if (qh_USEfindbestnew)
       qh->findbestnew= True;
     else {
       FORALLnew_facets {
         if (!newfacet->simplicial) {
           qh->findbestnew= True;  /* use qh_findbestnew instead of qh_findbest*/
           break;
         }
       }
     }
   }else if (qh->BESToutside)
     qh->findbestnew= True;
   qh_partitionvisible(qh /*qh.visible_list*/, !qh_ALL, &numpoints);
   qh->findbestnew= False;
   qh->findbest_notsharp= False;
   zinc_(Zpbalance);
   pbalance= numpoints - (realT) qh->hull_dim /* assumes all points extreme */
                 * (qh->num_points - qh->num_vertices)/qh->num_vertices;
   wadd_(Wpbalance, pbalance);
   wadd_(Wpbalance2, pbalance * pbalance);
   qh_deletevisible(qh /*qh.visible_list*/);
   zmax_(Zmaxvertex, qh->num_vertices);
   qh->NEWfacets= False;
   if (qh->IStracing >= 4) {
     if (qh->num_facets < 2000)
       qh_printlists(qh);
     qh_printfacetlist(qh, qh->newfacet_list, NULL, True);
     qh_checkpolygon(qh, qh->facet_list);
   }else if (qh->CHECKfrequently) {
     if (qh->num_facets < 50)
       qh_checkpolygon(qh, qh->facet_list);
     else
       qh_checkpolygon(qh, qh->newfacet_list);
   }
   if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1)
     return False;
   qh_resetlists(qh, True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
   /* qh_triangulate(qh); to test qh.TRInormals */
   trace2((qh, qh->ferr, 2056, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",
     qh_pointid(qh, furthest), numnew, newbalance, pbalance));
   return True;
 } /* addpoint */
 
 /*---------------------------------
 
   qh_build_withrestart(qh)
     allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
        qh_errexit always undoes qh_build_withrestart()
     qh.FIRSTpoint/qh.NUMpoints is point array
        it may be moved by qh_joggleinput(qh)
 */
 void qh_build_withrestart(qhT *qh) {
   int restart;
 
   qh->ALLOWrestart= True;
   while (True) {
     restart= setjmp(qh->restartexit); /* simple statement for CRAY J916 */
     if (restart) {       /* only from qh_precision() */
       zzinc_(Zretry);
       wmax_(Wretrymax, qh->JOGGLEmax);
       /* QH7078 warns about using 'TCn' with 'QJn' */
       qh->STOPcone= -1; /* if break from joggle, prevents normal output */
     }
     if (!qh->RERUN && qh->JOGGLEmax < REALmax/2) {
       if (qh->build_cnt > qh_JOGGLEmaxretry) {
         qh_fprintf(qh, qh->ferr, 6229, "qhull precision error: %d attempts to construct a convex hull\n\
         with joggled input.  Increase joggle above 'QJ%2.2g'\n\
         or modify qh_JOGGLE... parameters in user.h\n",
            qh->build_cnt, qh->JOGGLEmax);
         qh_errexit(qh, qh_ERRqhull, NULL, NULL);
       }
       if (qh->build_cnt && !restart)
         break;
     }else if (qh->build_cnt && qh->build_cnt >= qh->RERUN)
       break;
     qh->STOPcone= 0;
     qh_freebuild(qh, True);  /* first call is a nop */
     qh->build_cnt++;
     if (!qh->qhull_optionsiz)
       qh->qhull_optionsiz= (int)strlen(qh->qhull_options);   /* WARN64 */
     else {
       qh->qhull_options [qh->qhull_optionsiz]= '\0';
       qh->qhull_optionlen= qh_OPTIONline;  /* starts a new line */
     }
     qh_option(qh, "_run", &qh->build_cnt, NULL);
     if (qh->build_cnt == qh->RERUN) {
       qh->IStracing= qh->TRACElastrun;  /* duplicated from qh_initqhull_globals */
       if (qh->TRACEpoint != -1 || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
         qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);
         qh->IStracing= 0;
       }
       qh->qhmem.IStracing= qh->IStracing;
     }
     if (qh->JOGGLEmax < REALmax/2)
       qh_joggleinput(qh);
     qh_initbuild(qh);
     qh_buildhull(qh);
     if (qh->JOGGLEmax < REALmax/2 && !qh->MERGING)
       qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
   }
   qh->ALLOWrestart= False;
 } /* qh_build_withrestart */
 
 /*---------------------------------
 
   qh_buildhull(qh)
     construct a convex hull by adding outside points one at a time
 
   returns:
 
   notes:
     may be called multiple times
     checks facet and vertex lists for incorrect flags
     to recover from STOPcone, call qh_deletevisible and qh_resetlists
 
   design:
     check visible facet and newfacet flags
     check newlist vertex flags and qh.STOPcone/STOPpoint
     for each facet with a furthest outside point
       add point to facet
       exit if qh.STOPcone or qh.STOPpoint requested
     if qh.NARROWhull for initial simplex
       partition remaining outside points to coplanar sets
 */
 void qh_buildhull(qhT *qh) {
   facetT *facet;
   pointT *furthest;
   vertexT *vertex;
   int id;
 
   trace1((qh, qh->ferr, 1037, "qh_buildhull: start build hull\n"));
   FORALLfacets {
     if (facet->visible || facet->newfacet) {
       qh_fprintf(qh, qh->ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
                    facet->id);
       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     }
   }
   FORALLvertices {
     if (vertex->newlist) {
       qh_fprintf(qh, qh->ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
                    vertex->id);
       qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }
     id= qh_pointid(qh, vertex->point);
     if ((qh->STOPpoint>0 && id == qh->STOPpoint-1) ||
         (qh->STOPpoint<0 && id == -qh->STOPpoint-1) ||
         (qh->STOPcone>0 && id == qh->STOPcone-1)) {
       trace1((qh, qh->ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
       return;
     }
   }
   qh->facet_next= qh->facet_list;      /* advance facet when processed */
   while ((furthest= qh_nextfurthest(qh, &facet))) {
     qh->num_outside--;  /* if ONLYmax, furthest may not be outside */
     if (!qh_addpoint(qh, furthest, facet, qh->ONLYmax))
       break;
   }
   if (qh->NARROWhull) /* move points from outsideset to coplanarset */
     qh_outcoplanar(qh /* facet_list */ );
   if (qh->num_outside && !furthest) {
     qh_fprintf(qh, qh->ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh->num_outside);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   trace1((qh, qh->ferr, 1039, "qh_buildhull: completed the hull construction\n"));
 } /* buildhull */
 
 
 /*---------------------------------
 
   qh_buildtracing(qh, furthest, facet )
     trace an iteration of qh_buildhull() for furthest point and facet
     if !furthest, prints progress message
 
   returns:
     tracks progress with qh.lastreport
     updates qh.furthest_id (-3 if furthest is NULL)
     also resets visit_id, vertext_visit on wrap around
 
   see:
     qh_tracemerging()
 
   design:
     if !furthest
       print progress message
       exit
     if 'TFn' iteration
       print progress message
     else if tracing
       trace furthest point and facet
     reset qh.visit_id and qh.vertex_visit if overflow may occur
     set qh.furthest_id for tracing
 */
 void qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet) {
   realT dist= 0;
   float cpu;
   int total, furthestid;
   time_t timedata;
   struct tm *tp;
   vertexT *vertex;
 
   qh->old_randomdist= qh->RANDOMdist;
   qh->RANDOMdist= False;
   if (!furthest) {
     time(&timedata);
     tp= localtime(&timedata);
     cpu= (float)qh_CPUclock - (float)qh->hulltime;
     cpu /= (float)qh_SECticks;
     total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
     qh_fprintf(qh, qh->ferr, 8118, "\n\
 At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
  The current hull contains %d facets and %d vertices.  Last point was p%d\n",
       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
       total, qh->num_facets, qh->num_vertices, qh->furthest_id);
     return;
   }
   furthestid= qh_pointid(qh, furthest);
   if (qh->TRACEpoint == furthestid) {
     qh->IStracing= qh->TRACElevel;
     qh->qhmem.IStracing= qh->TRACElevel;
   }else if (qh->TRACEpoint != -1 && qh->TRACEdist < REALmax/2) {
     qh->IStracing= 0;
     qh->qhmem.IStracing= 0;
   }
   if (qh->REPORTfreq && (qh->facet_id-1 > qh->lastreport+qh->REPORTfreq)) {
     qh->lastreport= qh->facet_id-1;
     time(&timedata);
     tp= localtime(&timedata);
     cpu= (float)qh_CPUclock - (float)qh->hulltime;
     cpu /= (float)qh_SECticks;
     total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
     zinc_(Zdistio);
     qh_distplane(qh, furthest, facet, &dist);
     qh_fprintf(qh, qh->ferr, 8119, "\n\
 At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
  The current hull contains %d facets and %d vertices.  There are %d\n\
  outside points.  Next is point p%d(v%d), %2.2g above f%d.\n",
       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
       total, qh->num_facets, qh->num_vertices, qh->num_outside+1,
       furthestid, qh->vertex_id, dist, getid_(facet));
   }else if (qh->IStracing >=1) {
     cpu= (float)qh_CPUclock - (float)qh->hulltime;
     cpu /= (float)qh_SECticks;
     qh_distplane(qh, furthest, facet, &dist);
     qh_fprintf(qh, qh->ferr, 8120, "qh_addpoint: add p%d(v%d) to hull of %d facets(%2.2g above f%d) and %d outside at %4.4g CPU secs.  Previous was p%d.\n",
       furthestid, qh->vertex_id, qh->num_facets, dist,
       getid_(facet), qh->num_outside+1, cpu, qh->furthest_id);
   }
   zmax_(Zvisit2max, (int)qh->visit_id/2);
   if (qh->visit_id > (unsigned) INT_MAX) {
     zinc_(Zvisit);
     qh->visit_id= 0;
     FORALLfacets
       facet->visitid= 0;
   }
   zmax_(Zvvisit2max, (int)qh->vertex_visit/2);
   if (qh->vertex_visit > (unsigned) INT_MAX/2) { /* 31 bits */
     zinc_(Zvvisit);
     qh->vertex_visit= 0;
     FORALLvertices
       vertex->visitid= 0;
   }
   qh->furthest_id= furthestid;
   qh->RANDOMdist= qh->old_randomdist;
 } /* buildtracing */
 
 /*---------------------------------
 
   qh_errexit2(qh, exitcode, facet, otherfacet )
     return exitcode to system after an error
     report two facets
 
   returns:
     assumes exitcode non-zero
 
   see:
     normally use qh_errexit() in user.c(reports a facet and a ridge)
 */
 void qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet) {
 
   qh_errprint(qh, "ERRONEOUS", facet, otherfacet, NULL, NULL);
   qh_errexit(qh, exitcode, NULL, NULL);
 } /* errexit2 */
 
 
 /*---------------------------------
 
   qh_findhorizon(qh, point, facet, goodvisible, goodhorizon )
     given a visible facet, find the point's horizon and visible facets
     for all facets, !facet-visible
 
   returns:
     returns qh.visible_list/num_visible with all visible facets
       marks visible facets with ->visible
     updates count of good visible and good horizon facets
     updates qh.max_outside, qh.max_vertex, facet->maxoutside
 
   see:
     similar to qh_delpoint()
 
   design:
     move facet to qh.visible_list at end of qh.facet_list
     for all visible facets
      for each unvisited neighbor of a visible facet
        compute distance of point to neighbor
        if point above neighbor
          move neighbor to end of qh.visible_list
        else if point is coplanar with neighbor
          update qh.max_outside, qh.max_vertex, neighbor->maxoutside
          mark neighbor coplanar (will create a samecycle later)
          update horizon statistics
 */
 void qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
   facetT *neighbor, **neighborp, *visible;
   int numhorizon= 0, coplanar= 0;
   realT dist;
 
   trace1((qh, qh->ferr, 1040,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(qh, point),facet->id));
   *goodvisible= *goodhorizon= 0;
   zinc_(Ztotvisible);
   qh_removefacet(qh, facet);  /* visible_list at end of qh->facet_list */
   qh_appendfacet(qh, facet);
   qh->num_visible= 1;
   if (facet->good)
     (*goodvisible)++;
   qh->visible_list= facet;
   facet->visible= True;
   facet->f.replace= NULL;
   if (qh->IStracing >=4)
     qh_errprint(qh, "visible", facet, NULL, NULL, NULL);
   qh->visit_id++;
   FORALLvisible_facets {
     if (visible->tricoplanar && !qh->TRInormals) {
       qh_fprintf(qh, qh->ferr, 6230, "Qhull internal error (qh_findhorizon): does not work for tricoplanar facets.  Use option 'Q11'\n");
       qh_errexit(qh, qh_ERRqhull, visible, NULL);
     }
     visible->visitid= qh->visit_id;
     FOREACHneighbor_(visible) {
       if (neighbor->visitid == qh->visit_id)
         continue;
       neighbor->visitid= qh->visit_id;
       zzinc_(Znumvisibility);
       qh_distplane(qh, point, neighbor, &dist);
       if (dist > qh->MINvisible) {
         zinc_(Ztotvisible);
         qh_removefacet(qh, neighbor);  /* append to end of qh->visible_list */
         qh_appendfacet(qh, neighbor);
         neighbor->visible= True;
         neighbor->f.replace= NULL;
         qh->num_visible++;
         if (neighbor->good)
           (*goodvisible)++;
         if (qh->IStracing >=4)
           qh_errprint(qh, "visible", neighbor, NULL, NULL, NULL);
       }else {
         if (dist > - qh->MAXcoplanar) {
           neighbor->coplanar= True;
           zzinc_(Zcoplanarhorizon);
           qh_precision(qh, "coplanar horizon");
           coplanar++;
           if (qh->MERGING) {
             if (dist > 0) {
               maximize_(qh->max_outside, dist);
               maximize_(qh->max_vertex, dist);
 #if qh_MAXoutside
               maximize_(neighbor->maxoutside, dist);
 #endif
             }else
               minimize_(qh->min_vertex, dist);  /* due to merge later */
           }
           trace2((qh, qh->ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh->MINvisible(%2.7g)\n",
               qh_pointid(qh, point), neighbor->id, dist, qh->MINvisible));
         }else
           neighbor->coplanar= False;
         zinc_(Ztothorizon);
         numhorizon++;
         if (neighbor->good)
           (*goodhorizon)++;
         if (qh->IStracing >=4)
           qh_errprint(qh, "horizon", neighbor, NULL, NULL, NULL);
       }
     }
   }
   if (!numhorizon) {
     qh_precision(qh, "empty horizon");
     qh_fprintf(qh, qh->ferr, 6168, "qhull precision error (qh_findhorizon): empty horizon\n\
 QhullPoint p%d was above all facets.\n", qh_pointid(qh, point));
     qh_printfacetlist(qh, qh->facet_list, NULL, True);
     qh_errexit(qh, qh_ERRprec, NULL, NULL);
   }
   trace1((qh, qh->ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",
        numhorizon, *goodhorizon, qh->num_visible, *goodvisible, coplanar));
   if (qh->IStracing >= 4 && qh->num_facets < 50)
     qh_printlists(qh);
 } /* findhorizon */
 
 /*---------------------------------
 
   qh_nextfurthest(qh, visible )
     returns next furthest point and visible facet for qh_addpoint()
     starts search at qh.facet_next
 
   returns:
     removes furthest point from outside set
     NULL if none available
     advances qh.facet_next over facets with empty outside sets
 
   design:
     for each facet from qh.facet_next
       if empty outside set
         advance qh.facet_next
       else if qh.NARROWhull
         determine furthest outside point
         if furthest point is not outside
           advance qh.facet_next(point will be coplanar)
     remove furthest point from outside set
 */
 pointT *qh_nextfurthest(qhT *qh, facetT **visible) {
   facetT *facet;
   int size, idx;
   realT randr, dist;
   pointT *furthest;
 
   while ((facet= qh->facet_next) != qh->facet_tail) {
     if (!facet->outsideset) {
       qh->facet_next= facet->next;
       continue;
     }
     SETreturnsize_(facet->outsideset, size);
     if (!size) {
       qh_setfree(qh, &facet->outsideset);
       qh->facet_next= facet->next;
       continue;
     }
     if (qh->NARROWhull) {
       if (facet->notfurthest)
         qh_furthestout(qh, facet);
       furthest= (pointT*)qh_setlast(facet->outsideset);
 #if qh_COMPUTEfurthest
       qh_distplane(qh, furthest, facet, &dist);
       zinc_(Zcomputefurthest);
 #else
       dist= facet->furthestdist;
 #endif
       if (dist < qh->MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
         qh->facet_next= facet->next;
         continue;
       }
     }
     if (!qh->RANDOMoutside && !qh->VIRTUALmemory) {
       if (qh->PICKfurthest) {
         qh_furthestnext(qh /* qh->facet_list */);
         facet= qh->facet_next;
       }
       *visible= facet;
       return((pointT*)qh_setdellast(facet->outsideset));
     }
     if (qh->RANDOMoutside) {
       int outcoplanar = 0;
       if (qh->NARROWhull) {
         FORALLfacets {
           if (facet == qh->facet_next)
             break;
           if (facet->outsideset)
             outcoplanar += qh_setsize(qh, facet->outsideset);
         }
       }
       randr= qh_RANDOMint;
       randr= randr/(qh_RANDOMmax+1);
       idx= (int)floor((qh->num_outside - outcoplanar) * randr);
       FORALLfacet_(qh->facet_next) {
         if (facet->outsideset) {
           SETreturnsize_(facet->outsideset, size);
           if (!size)
             qh_setfree(qh, &facet->outsideset);
           else if (size > idx) {
             *visible= facet;
             return((pointT*)qh_setdelnth(qh, facet->outsideset, idx));
           }else
             idx -= size;
         }
       }
       qh_fprintf(qh, qh->ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
               qh->num_outside, idx+1, randr);
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }else { /* VIRTUALmemory */
       facet= qh->facet_tail->previous;
       if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {
         if (facet->outsideset)
           qh_setfree(qh, &facet->outsideset);
         qh_removefacet(qh, facet);
         qh_prependfacet(qh, facet, &qh->facet_list);
         continue;
       }
       *visible= facet;
       return furthest;
     }
   }
   return NULL;
 } /* nextfurthest */
 
 /*---------------------------------
 
   qh_partitionall(qh, vertices, points, numpoints )
     partitions all points in points/numpoints to the outsidesets of facets
     vertices= vertices in qh.facet_list(!partitioned)
 
   returns:
     builds facet->outsideset
     does not partition qh.GOODpoint
     if qh.ONLYgood && !qh.MERGING,
       does not partition qh.GOODvertex
 
   notes:
     faster if qh.facet_list sorted by anticipated size of outside set
 
   design:
     initialize pointset with all points
     remove vertices from pointset
     remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
     for all facets
       for all remaining points in pointset
         compute distance from point to facet
         if point is outside facet
           remove point from pointset (by not reappending)
           update bestpoint
           append point or old bestpoint to facet's outside set
       append bestpoint to facet's outside set (furthest)
     for all points remaining in pointset
       partition point into facets' outside sets and coplanar sets
 */
 void qh_partitionall(qhT *qh, setT *vertices, pointT *points, int numpoints){
   setT *pointset;
   vertexT *vertex, **vertexp;
   pointT *point, **pointp, *bestpoint;
   int size, point_i, point_n, point_end, remaining, i, id;
   facetT *facet;
   realT bestdist= -REALmax, dist, distoutside;
 
   trace1((qh, qh->ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));
   pointset= qh_settemp(qh, numpoints);
   qh->num_outside= 0;
   pointp= SETaddr_(pointset, pointT);
   for (i=numpoints, point= points; i--; point += qh->hull_dim)
     *(pointp++)= point;
   qh_settruncate(qh, pointset, numpoints);
   FOREACHvertex_(vertices) {
     if ((id= qh_pointid(qh, vertex->point)) >= 0)
       SETelem_(pointset, id)= NULL;
   }
   id= qh_pointid(qh, qh->GOODpointp);
   if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
     SETelem_(pointset, id)= NULL;
   if (qh->GOODvertexp && qh->ONLYgood && !qh->MERGING) { /* matches qhull()*/
     if ((id= qh_pointid(qh, qh->GOODvertexp)) >= 0)
       SETelem_(pointset, id)= NULL;
   }
   if (!qh->BESToutside) {  /* matches conditional for qh_partitionpoint below */
     distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
     zval_(Ztotpartition)= qh->num_points - qh->hull_dim - 1; /*misses GOOD... */
     remaining= qh->num_facets;
     point_end= numpoints;
     FORALLfacets {
       size= point_end/(remaining--) + 100;
       facet->outsideset= qh_setnew(qh, size);
       bestpoint= NULL;
       point_end= 0;
       FOREACHpoint_i_(qh, pointset) {
         if (point) {
           zzinc_(Zpartitionall);
           qh_distplane(qh, point, facet, &dist);
           if (dist < distoutside)
             SETelem_(pointset, point_end++)= point;
           else {
             qh->num_outside++;
             if (!bestpoint) {
               bestpoint= point;
               bestdist= dist;
             }else if (dist > bestdist) {
               qh_setappend(qh, &facet->outsideset, bestpoint);
               bestpoint= point;
               bestdist= dist;
             }else
               qh_setappend(qh, &facet->outsideset, point);
           }
         }
       }
       if (bestpoint) {
         qh_setappend(qh, &facet->outsideset, bestpoint);
 #if !qh_COMPUTEfurthest
         facet->furthestdist= bestdist;
 #endif
       }else
         qh_setfree(qh, &facet->outsideset);
       qh_settruncate(qh, pointset, point_end);
     }
   }
   /* if !qh->BESToutside, pointset contains points not assigned to outsideset */
   if (qh->BESToutside || qh->MERGING || qh->KEEPcoplanar || qh->KEEPinside) {
     qh->findbestnew= True;
     FOREACHpoint_i_(qh, pointset) {
       if (point)
         qh_partitionpoint(qh, point, qh->facet_list);
     }
     qh->findbestnew= False;
   }
   zzadd_(Zpartitionall, zzval_(Zpartition));
   zzval_(Zpartition)= 0;
   qh_settempfree(qh, &pointset);
   if (qh->IStracing >= 4)
     qh_printfacetlist(qh, qh->facet_list, NULL, True);
 } /* partitionall */
 
 
 /*---------------------------------
 
   qh_partitioncoplanar(qh, point, facet, dist )
     partition coplanar point to a facet
     dist is distance from point to facet
     if dist NULL,
       searches for bestfacet and does nothing if inside
     if qh.findbestnew set,
       searches new facets instead of using qh_findbest()
 
   returns:
     qh.max_ouside updated
     if qh.KEEPcoplanar or qh.KEEPinside
       point assigned to best coplanarset
 
   notes:
     facet->maxoutside is updated at end by qh_check_maxout
 
   design:
     if dist undefined
       find best facet for point
       if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
         exit
     if keeping coplanar/nearinside/inside points
       if point is above furthest coplanar point
         append point to coplanar set (it is the new furthest)
         update qh.max_outside
       else
         append point one before end of coplanar set
     else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
     and bestfacet is more than perpendicular to facet
       repartition the point using qh_findbest() -- it may be put on an outsideset
     else
       update qh.max_outside
 */
 void qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist) {
   facetT *bestfacet;
   pointT *oldfurthest;
   realT bestdist, dist2= 0, angle;
   int numpart= 0, oldfindbest;
   boolT isoutside;
 
   qh->WAScoplanar= True;
   if (!dist) {
     if (qh->findbestnew)
       bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
     else
       bestfacet= qh_findbest(qh, point, facet, qh_ALL, !qh_ISnewfacets, qh->DELAUNAY,
                           &bestdist, &isoutside, &numpart);
     zinc_(Ztotpartcoplanar);
     zzadd_(Zpartcoplanar, numpart);
     if (!qh->DELAUNAY && !qh->KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
       if (qh->KEEPnearinside) {
         if (bestdist < -qh->NEARinside) {
           zinc_(Zcoplanarinside);
           trace4((qh, qh->ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n",
                   qh_pointid(qh, point), bestfacet->id, bestdist, qh->findbestnew));
           return;
         }
       }else if (bestdist < -qh->MAXcoplanar) {
           trace4((qh, qh->ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n",
                   qh_pointid(qh, point), bestfacet->id, bestdist, qh->findbestnew));
         zinc_(Zcoplanarinside);
         return;
       }
     }
   }else {
     bestfacet= facet;
     bestdist= *dist;
   }
   if (bestdist > qh->max_outside) {
     if (!dist && facet != bestfacet) {
       zinc_(Zpartangle);
       angle= qh_getangle(qh, facet->normal, bestfacet->normal);
       if (angle < 0) {
         /* typically due to deleted vertex and coplanar facets, e.g.,
              RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
         zinc_(Zpartflip);
         trace2((qh, qh->ferr, 2058, "qh_partitioncoplanar: repartition point p%d from f%d.  It is above flipped facet f%d dist %2.2g\n",
                 qh_pointid(qh, point), facet->id, bestfacet->id, bestdist));
         oldfindbest= qh->findbestnew;
         qh->findbestnew= False;
         qh_partitionpoint(qh, point, bestfacet);
         qh->findbestnew= oldfindbest;
         return;
       }
     }
     qh->max_outside= bestdist;
     if (bestdist > qh->TRACEdist) {
       qh_fprintf(qh, qh->ferr, 8122, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",
                      qh_pointid(qh, point), facet->id, bestdist, bestfacet->id, qh->furthest_id);
       qh_errprint(qh, "DISTANT", facet, bestfacet, NULL, NULL);
     }
   }
   if (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside) {
     oldfurthest= (pointT*)qh_setlast(bestfacet->coplanarset);
     if (oldfurthest) {
       zinc_(Zcomputefurthest);
       qh_distplane(qh, oldfurthest, bestfacet, &dist2);
     }
     if (!oldfurthest || dist2 < bestdist)
       qh_setappend(qh, &bestfacet->coplanarset, point);
     else
       qh_setappend2ndlast(qh, &bestfacet->coplanarset, point);
   }
   trace4((qh, qh->ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d(or inside) dist %2.2g\n",
           qh_pointid(qh, point), bestfacet->id, bestdist));
 } /* partitioncoplanar */
 
 /*---------------------------------
 
   qh_partitionpoint(qh, point, facet )
     assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
     if qh.findbestnew
       uses qh_findbestnew() to search all new facets
     else
       uses qh_findbest()
 
   notes:
     after qh_distplane(), this and qh_findbest() are most expensive in 3-d
 
   design:
     find best facet for point
       (either exhaustive search of new facets or directed search from facet)
     if qh.NARROWhull
       retain coplanar and nearinside points as outside points
     if point is outside bestfacet
       if point above furthest point for bestfacet
         append point to outside set (it becomes the new furthest)
         if outside set was empty
           move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
         update bestfacet->furthestdist
       else
         append point one before end of outside set
     else if point is coplanar to bestfacet
       if keeping coplanar points or need to update qh.max_outside
         partition coplanar point into bestfacet
     else if near-inside point
       partition as coplanar point into bestfacet
     else is an inside point
       if keeping inside points
         partition as coplanar point into bestfacet
 */
 void qh_partitionpoint(qhT *qh, pointT *point, facetT *facet) {
   realT bestdist;
   boolT isoutside;
   facetT *bestfacet;
   int numpart;
 #if qh_COMPUTEfurthest
   realT dist;
 #endif
 
   if (qh->findbestnew)
     bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh->BESToutside, &isoutside, &numpart);
   else
     bestfacet= qh_findbest(qh, point, facet, qh->BESToutside, qh_ISnewfacets, !qh_NOupper,
                           &bestdist, &isoutside, &numpart);
   zinc_(Ztotpartition);
   zzadd_(Zpartition, numpart);
   if (qh->NARROWhull) {
     if (qh->DELAUNAY && !isoutside && bestdist >= -qh->MAXcoplanar)
       qh_precision(qh, "nearly incident point(narrow hull)");
     if (qh->KEEPnearinside) {
       if (bestdist >= -qh->NEARinside)
         isoutside= True;
     }else if (bestdist >= -qh->MAXcoplanar)
       isoutside= True;
   }
 
   if (isoutside) {
     if (!bestfacet->outsideset
     || !qh_setlast(bestfacet->outsideset)) {
       qh_setappend(qh, &(bestfacet->outsideset), point);
       if (!bestfacet->newfacet) {
         qh_removefacet(qh, bestfacet);  /* make sure it's after qh->facet_next */
         qh_appendfacet(qh, bestfacet);
       }
 #if !qh_COMPUTEfurthest
       bestfacet->furthestdist= bestdist;
 #endif
     }else {
 #if qh_COMPUTEfurthest
       zinc_(Zcomputefurthest);
       qh_distplane(qh, oldfurthest, bestfacet, &dist);
       if (dist < bestdist)
         qh_setappend(qh, &(bestfacet->outsideset), point);
       else
         qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
 #else
       if (bestfacet->furthestdist < bestdist) {
         qh_setappend(qh, &(bestfacet->outsideset), point);
         bestfacet->furthestdist= bestdist;
       }else
         qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
 #endif
     }
     qh->num_outside++;
     trace4((qh, qh->ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d new? %d (or narrowhull)\n",
           qh_pointid(qh, point), bestfacet->id, bestfacet->newfacet));
   }else if (qh->DELAUNAY || bestdist >= -qh->MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
     zzinc_(Zcoplanarpart);
     if (qh->DELAUNAY)
       qh_precision(qh, "nearly incident point");
     if ((qh->KEEPcoplanar + qh->KEEPnearinside) || bestdist > qh->max_outside)
       qh_partitioncoplanar(qh, point, bestfacet, &bestdist);
     else {
       trace4((qh, qh->ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
           qh_pointid(qh, point), bestfacet->id));
     }
   }else if (qh->KEEPnearinside && bestdist > -qh->NEARinside) {
     zinc_(Zpartnear);
     qh_partitioncoplanar(qh, point, bestfacet, &bestdist);
   }else {
     zinc_(Zpartinside);
     trace4((qh, qh->ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
           qh_pointid(qh, point), bestfacet->id, bestdist));
     if (qh->KEEPinside)
       qh_partitioncoplanar(qh, point, bestfacet, &bestdist);
   }
 } /* partitionpoint */
 
 /*---------------------------------
 
   qh_partitionvisible(qh, allpoints, numoutside )
     partitions points in visible facets to qh.newfacet_list
     qh.visible_list= visible facets
     for visible facets
       1st neighbor (if any) points to a horizon facet or a new facet
     if allpoints(!used),
       repartitions coplanar points
 
   returns:
     updates outside sets and coplanar sets of qh.newfacet_list
     updates qh.num_outside (count of outside points)
 
   notes:
     qh.findbest_notsharp should be clear (extra work if set)
 
   design:
     for all visible facets with outside set or coplanar set
       select a newfacet for visible facet
       if outside set
         partition outside set into new facets
       if coplanar set and keeping coplanar/near-inside/inside points
         if allpoints
           partition coplanar set into new facets, may be assigned outside
         else
           partition coplanar set into coplanar sets of new facets
     for each deleted vertex
       if allpoints
         partition vertex into new facets, may be assigned outside
       else
         partition vertex into coplanar sets of new facets
 */
 void qh_partitionvisible(qhT *qh /*qh.visible_list*/, boolT allpoints, int *numoutside) {
   facetT *visible, *newfacet;
   pointT *point, **pointp;
   int coplanar=0, size;
   unsigned count;
   vertexT *vertex, **vertexp;
 
   if (qh->ONLYmax)
     maximize_(qh->MINoutside, qh->max_vertex);
   *numoutside= 0;
   FORALLvisible_facets {
     if (!visible->outsideset && !visible->coplanarset)
       continue;
     newfacet= visible->f.replace;
     count= 0;
     while (newfacet && newfacet->visible) {
       newfacet= newfacet->f.replace;
       if (count++ > qh->facet_id)
         qh_infiniteloop(qh, visible);
     }
     if (!newfacet)
       newfacet= qh->newfacet_list;
     if (newfacet == qh->facet_tail) {
       qh_fprintf(qh, qh->ferr, 6170, "qhull precision error (qh_partitionvisible): all new facets deleted as\n        degenerate facets. Can not continue.\n");
       qh_errexit(qh, qh_ERRprec, NULL, NULL);
     }
     if (visible->outsideset) {
       size= qh_setsize(qh, visible->outsideset);
       *numoutside += size;
       qh->num_outside -= size;
       FOREACHpoint_(visible->outsideset)
         qh_partitionpoint(qh, point, newfacet);
     }
     if (visible->coplanarset && (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside)) {
       size= qh_setsize(qh, visible->coplanarset);
       coplanar += size;
       FOREACHpoint_(visible->coplanarset) {
         if (allpoints) /* not used */
           qh_partitionpoint(qh, point, newfacet);
         else
           qh_partitioncoplanar(qh, point, newfacet, NULL);
       }
     }
   }
   FOREACHvertex_(qh->del_vertices) {
     if (vertex->point) {
       if (allpoints) /* not used */
         qh_partitionpoint(qh, vertex->point, qh->newfacet_list);
       else
         qh_partitioncoplanar(qh, vertex->point, qh->newfacet_list, NULL);
     }
   }
   trace1((qh, qh->ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
 } /* partitionvisible */
 
 
 
 /*---------------------------------
 
   qh_precision(qh, reason )
     restart on precision errors if not merging and if 'QJn'
 */
 void qh_precision(qhT *qh, const char *reason) {
 
   if (qh->ALLOWrestart && !qh->PREmerge && !qh->MERGEexact) {
     if (qh->JOGGLEmax < REALmax/2) {
       trace0((qh, qh->ferr, 26, "qh_precision: qhull restart because of %s\n", reason));
       /* May be called repeatedly if qh->ALLOWrestart */
       longjmp(qh->restartexit, qh_ERRprec);
     }
   }
 } /* qh_precision */
 
 /*---------------------------------
 
   qh_printsummary(qh, fp )
     prints summary to fp
 
   notes:
     not in io_r.c so that user_eg.c can prevent io_r.c from loading
     qh_printsummary and qh_countfacets must match counts
 
   design:
     determine number of points, vertices, and coplanar points
     print summary
 */
 void qh_printsummary(qhT *qh, FILE *fp) {
   realT ratio, outerplane, innerplane;
   float cpu;
   int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;
   int goodused;
   facetT *facet;
   const char *s;
   int numdel= zzval_(Zdelvertextot);
   int numtricoplanars= 0;
 
   size= qh->num_points + qh_setsize(qh, qh->other_points);
   numvertices= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
   id= qh_pointid(qh, qh->GOODpointp);
   FORALLfacets {
     if (facet->coplanarset)
       numcoplanars += qh_setsize(qh, facet->coplanarset);
     if (facet->good) {
       if (facet->simplicial) {
         if (facet->keepcentrum && facet->tricoplanar)
           numtricoplanars++;
       }else if (qh_setsize(qh, facet->vertices) != qh->hull_dim)
         nonsimplicial++;
     }
   }
   if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
     size--;
   if (qh->STOPcone || qh->STOPpoint)
       qh_fprintf(qh, fp, 9288, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");
   if (qh->UPPERdelaunay)
     goodused= qh->GOODvertex + qh->GOODpoint + qh->SPLITthresholds;
   else if (qh->DELAUNAY)
     goodused= qh->GOODvertex + qh->GOODpoint + qh->GOODthreshold;
   else
     goodused= qh->num_good;
   nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
   if (qh->VORONOI) {
     if (qh->UPPERdelaunay)
       qh_fprintf(qh, fp, 9289, "\n\
 Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
     else
       qh_fprintf(qh, fp, 9290, "\n\
 Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
     qh_fprintf(qh, fp, 9291, "  Number of Voronoi regions%s: %d\n",
               qh->ATinfinity ? " and at-infinity" : "", numvertices);
     if (numdel)
       qh_fprintf(qh, fp, 9292, "  Total number of deleted points due to merging: %d\n", numdel);
     if (numcoplanars - numdel > 0)
       qh_fprintf(qh, fp, 9293, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
     else if (size - numvertices - numdel > 0)
       qh_fprintf(qh, fp, 9294, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
     qh_fprintf(qh, fp, 9295, "  Number of%s Voronoi vertices: %d\n",
               goodused ? " 'good'" : "", qh->num_good);
     if (nonsimplicial)
       qh_fprintf(qh, fp, 9296, "  Number of%s non-simplicial Voronoi vertices: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }else if (qh->DELAUNAY) {
     if (qh->UPPERdelaunay)
       qh_fprintf(qh, fp, 9297, "\n\
 Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
     else
       qh_fprintf(qh, fp, 9298, "\n\
 Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
     qh_fprintf(qh, fp, 9299, "  Number of input sites%s: %d\n",
               qh->ATinfinity ? " and at-infinity" : "", numvertices);
     if (numdel)
       qh_fprintf(qh, fp, 9300, "  Total number of deleted points due to merging: %d\n", numdel);
     if (numcoplanars - numdel > 0)
       qh_fprintf(qh, fp, 9301, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
     else if (size - numvertices - numdel > 0)
       qh_fprintf(qh, fp, 9302, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
     qh_fprintf(qh, fp, 9303, "  Number of%s Delaunay regions: %d\n",
               goodused ? " 'good'" : "", qh->num_good);
     if (nonsimplicial)
       qh_fprintf(qh, fp, 9304, "  Number of%s non-simplicial Delaunay regions: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }else if (qh->HALFspace) {
     qh_fprintf(qh, fp, 9305, "\n\
 Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
     qh_fprintf(qh, fp, 9306, "  Number of halfspaces: %d\n", size);
     qh_fprintf(qh, fp, 9307, "  Number of non-redundant halfspaces: %d\n", numvertices);
     if (numcoplanars) {
       if (qh->KEEPinside && qh->KEEPcoplanar)
         s= "similar and redundant";
       else if (qh->KEEPinside)
         s= "redundant";
       else
         s= "similar";
       qh_fprintf(qh, fp, 9308, "  Number of %s halfspaces: %d\n", s, numcoplanars);
     }
     qh_fprintf(qh, fp, 9309, "  Number of intersection points: %d\n", qh->num_facets - qh->num_visible);
     if (goodused)
       qh_fprintf(qh, fp, 9310, "  Number of 'good' intersection points: %d\n", qh->num_good);
     if (nonsimplicial)
       qh_fprintf(qh, fp, 9311, "  Number of%s non-simplicial intersection points: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }else {
     qh_fprintf(qh, fp, 9312, "\n\
 Convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
     qh_fprintf(qh, fp, 9313, "  Number of vertices: %d\n", numvertices);
     if (numcoplanars) {
       if (qh->KEEPinside && qh->KEEPcoplanar)
         s= "coplanar and interior";
       else if (qh->KEEPinside)
         s= "interior";
       else
         s= "coplanar";
       qh_fprintf(qh, fp, 9314, "  Number of %s points: %d\n", s, numcoplanars);
     }
     qh_fprintf(qh, fp, 9315, "  Number of facets: %d\n", qh->num_facets - qh->num_visible);
     if (goodused)
       qh_fprintf(qh, fp, 9316, "  Number of 'good' facets: %d\n", qh->num_good);
     if (nonsimplicial)
       qh_fprintf(qh, fp, 9317, "  Number of%s non-simplicial facets: %d\n",
               goodused ? " 'good'" : "", nonsimplicial);
   }
   if (numtricoplanars)
       qh_fprintf(qh, fp, 9318, "  Number of triangulated facets: %d\n", numtricoplanars);
   qh_fprintf(qh, fp, 9319, "\nStatistics for: %s | %s",
                       qh->rbox_command, qh->qhull_command);
   if (qh->ROTATErandom != INT_MIN)
     qh_fprintf(qh, fp, 9320, " QR%d\n\n", qh->ROTATErandom);
   else
     qh_fprintf(qh, fp, 9321, "\n\n");
   qh_fprintf(qh, fp, 9322, "  Number of points processed: %d\n", zzval_(Zprocessed));
   qh_fprintf(qh, fp, 9323, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
   if (qh->DELAUNAY)
     qh_fprintf(qh, fp, 9324, "  Number of facets in hull: %d\n", qh->num_facets - qh->num_visible);
   qh_fprintf(qh, fp, 9325, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
       zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
 #if 0  /* NOTE: must print before printstatistics() */
   {realT stddev, ave;
   qh_fprintf(qh, fp, 9326, "  average new facet balance: %2.2g\n",
           wval_(Wnewbalance)/zval_(Zprocessed));
   stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                  wval_(Wnewbalance2), &ave);
   qh_fprintf(qh, fp, 9327, "  new facet standard deviation: %2.2g\n", stddev);
   qh_fprintf(qh, fp, 9328, "  average partition balance: %2.2g\n",
           wval_(Wpbalance)/zval_(Zpbalance));
   stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                  wval_(Wpbalance2), &ave);
   qh_fprintf(qh, fp, 9329, "  partition standard deviation: %2.2g\n", stddev);
   }
 #endif
   if (nummerged) {
     qh_fprintf(qh, fp, 9330,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
           zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+
           zzval_(Zdistzero));
     qh_fprintf(qh, fp, 9331,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart));
     qh_fprintf(qh, fp, 9332,"  Number of merged facets: %d\n", nummerged);
   }
   if (!qh->RANDOMoutside && qh->QHULLfinished) {
     cpu= (float)qh->hulltime;
     cpu /= (float)qh_SECticks;
     wval_(Wcpu)= cpu;
     qh_fprintf(qh, fp, 9333, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
   }
   if (qh->RERUN) {
     if (!qh->PREmerge && !qh->MERGEexact)
       qh_fprintf(qh, fp, 9334, "  Percentage of runs with precision errors: %4.1f\n",
            zzval_(Zretry)*100.0/qh->build_cnt);  /* careful of order */
   }else if (qh->JOGGLEmax < REALmax/2) {
     if (zzval_(Zretry))
       qh_fprintf(qh, fp, 9335, "  After %d retries, input joggled by: %2.2g\n",
          zzval_(Zretry), qh->JOGGLEmax);
     else
       qh_fprintf(qh, fp, 9336, "  Input joggled by: %2.2g\n", qh->JOGGLEmax);
   }
   if (qh->totarea != 0.0)
     qh_fprintf(qh, fp, 9337, "  %s facet area:   %2.8g\n",
             zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totarea);
   if (qh->totvol != 0.0)
     qh_fprintf(qh, fp, 9338, "  %s volume:       %2.8g\n",
             zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totvol);
   if (qh->MERGING) {
     qh_outerinner(qh, NULL, &outerplane, &innerplane);
     if (outerplane > 2 * qh->DISTround) {
       qh_fprintf(qh, fp, 9339, "  Maximum distance of %spoint above facet: %2.2g",
             (qh->QHULLfinished ? "" : "merged "), outerplane);
       ratio= outerplane/(qh->ONEmerge + qh->DISTround);
       /* don't report ratio if MINoutside is large */
       if (ratio > 0.05 && 2* qh->ONEmerge > qh->MINoutside && qh->JOGGLEmax > REALmax/2)
         qh_fprintf(qh, fp, 9340, " (%.1fx)\n", ratio);
       else
         qh_fprintf(qh, fp, 9341, "\n");
     }
     if (innerplane < -2 * qh->DISTround) {
       qh_fprintf(qh, fp, 9342, "  Maximum distance of %svertex below facet: %2.2g",
             (qh->QHULLfinished ? "" : "merged "), innerplane);
       ratio= -innerplane/(qh->ONEmerge+qh->DISTround);
       if (ratio > 0.05 && qh->JOGGLEmax > REALmax/2)
         qh_fprintf(qh, fp, 9343, " (%.1fx)\n", ratio);
       else
         qh_fprintf(qh, fp, 9344, "\n");
     }
   }
   qh_fprintf(qh, fp, 9345, "\n");
 } /* printsummary */
 
 
diff --git a/src/libqhullr/libqhull_r.h b/src/libqhullr/libqhull_r.h
index ea75def..1d8187b 100644
--- a/src/libqhullr/libqhull_r.h
+++ b/src/libqhullr/libqhull_r.h
@@ -1,1090 +1,1090 @@
 /*
  ---------------------------------
 
    libqhull_r.h
    user-level header file for using qhull.a library
 
    see qh-qhull.htm, qhull_ra.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/libqhull_r.h#9 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/libqhull_r.h#10 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    includes function prototypes for libqhull_r.c, geom_r.c, global_r.c, io_r.c, user.c
 
    use mem_r.h for mem_r.c
    use qset_r.h for qset_r.c
 
    see unix_r.c for an example of using libqhull_r.h
 
    recompile qhull if you change this file
 */
 
 #ifndef qhDEFlibqhull
 #define qhDEFlibqhull 1
 
 /*=========================== -included files ==============*/
 
 #include "user_r.h"      /* user definable constants (e.g., realT) */
 
 #include "mem_r.h" 
 /* stat_r.h included realT */
 
 #include 
 #include 
 #include 
 #include 
 
 #ifndef __STDC__
 #ifndef __cplusplus
 #if     !_MSC_VER
 #error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
 #error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
 #error  your compiler is a standard C compiler, you can delete this warning from libqhull_r.h
 #endif
 #endif
 #endif
 
 /*============ constants and basic types ====================*/
 
 extern const char *qh_version; /* defined in global_r.c */
 
 /*----------------------------------
 
   coordT
     coordinates and coefficients are stored as realT (i.e., double)
 
   notes:
     Qhull works well if realT is 'float'.  If so joggle (QJ) is not effective.
 
     Could use 'float' for data and 'double' for calculations (realT vs. coordT)
       This requires many type casts, and adjusted error bounds.
       Also C compilers may do expressions in double anyway.
 */
 #define coordT realT
 
 /*----------------------------------
 
   pointT
     a point is an array of coordinates, usually qh.hull_dim
 */
 #define pointT coordT
 
 /*----------------------------------
 
   flagT
     Boolean flag as a bit
 */
 #define flagT unsigned int
 
 /*----------------------------------
 
   boolT
     boolean value, either True or False
 
   notes:
     needed for portability
     Use qh_False/qh_True as synonyms
 */
 #define boolT unsigned int
 #ifdef False
 #undef False
 #endif
 #ifdef True
 #undef True
 #endif
 #define False 0
 #define True 1
 #define qh_False 0
 #define qh_True 1
 
 #include "stat_r.h" 
 
 /*----------------------------------
 
   qh_CENTER
     to distinguish facet->center
 */
 typedef enum
 {
     qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
 }
 qh_CENTER;
 
 /*----------------------------------
 
   qh_PRINT
     output formats for printing (qh.PRINTout).
     'Fa' 'FV' 'Fc' 'FC'
 
 
    notes:
    some of these names are similar to qhT names.  The similar names are only
    used in switch statements in qh_printbegin() etc.
 */
 typedef enum {qh_PRINTnone= 0,
   qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
   qh_PRINTcoplanars, qh_PRINTcentrums,
   qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
   qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors,
   qh_PRINTnormals, qh_PRINTouter, qh_PRINTmaple, /* 'n' 'Fo' 'i' 'm' 'Fm' 'FM', 'o' */
   qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff,
   qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
   qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize,
   qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
   qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
   qh_PRINTEND} qh_PRINT;
 
 /*----------------------------------
 
   qh_ALL
     argument flag for selecting everything
 */
 #define qh_ALL      True
 #define qh_NOupper  True     /* argument for qh_findbest */
 #define qh_IScheckmax  True     /* argument for qh_findbesthorizon */
 #define qh_ISnewfacets  True     /* argument for qh_findbest */
 #define qh_RESETvisible  True     /* argument for qh_resetlists */
 
 /*----------------------------------
 
   qh_ERR
     Qhull exit codes, for indicating errors
     See: MSG_ERROR and MSG_WARNING [user.h]
 */
 #define qh_ERRnone  0    /* no error occurred during qhull */
 #define qh_ERRinput 1    /* input inconsistency */
 #define qh_ERRsingular 2 /* singular input data */
 #define qh_ERRprec  3    /* precision error */
 #define qh_ERRmem   4    /* insufficient memory, matches mem_r.h */
 #define qh_ERRqhull 5    /* internal error detected, matches mem_r.h */
 
 /*----------------------------------
 
 qh_FILEstderr
 Fake stderr to distinguish error output from normal output
 For C++ interface.  Must redefine qh_fprintf_qhull
 */
 #define qh_FILEstderr ((FILE*)1)
 
 /* ============ -structures- ====================
    each of the following structures is defined by a typedef
    all realT and coordT fields occur at the beginning of a structure
         (otherwise space may be wasted due to alignment)
    define all flags together and pack into 32-bit number
 */
 
 typedef struct vertexT vertexT;
 typedef struct ridgeT ridgeT;
 typedef struct facetT facetT;
 
 #ifndef DEFqhT
 #define DEFqhT 1
 typedef struct qhT qhT;          /* defined below */
 #endif
 
 #ifndef DEFsetT
 #define DEFsetT 1
 typedef struct setT setT;          /* defined in qset_r.h */
 #endif
 
 #ifndef DEFqhstatT
 #define DEFqhstatT 1
 typedef struct qhstatT qhstatT;    /* defined in stat_r.h */
 #endif
 
 /*----------------------------------
 
   facetT
     defines a facet
 
   notes:
    qhull() generates the hull as a list of facets.
 
   topological information:
     f.previous,next     doubly-linked list of facets
     f.vertices          set of vertices
     f.ridges            set of ridges
     f.neighbors         set of neighbors
     f.toporient         True if facet has top-orientation (else bottom)
 
   geometric information:
     f.offset,normal     hyperplane equation
     f.maxoutside        offset to outer plane -- all points inside
     f.center            centrum for testing convexity
     f.simplicial        True if facet is simplicial
     f.flipped           True if facet does not include qh.interior_point
 
   for constructing hull:
     f.visible           True if facet on list of visible facets (will be deleted)
     f.newfacet          True if facet on list of newly created facets
     f.coplanarset       set of points coplanar with this facet
                         (includes near-inside points for later testing)
     f.outsideset        set of points outside of this facet
     f.furthestdist      distance to furthest point of outside set
     f.visitid           marks visited facets during a loop
     f.replace           replacement facet for to-be-deleted, visible facets
     f.samecycle,newcycle cycle of facets for merging into horizon facet
 
   see below for other flags and fields
 */
 struct facetT {
 #if !qh_COMPUTEfurthest
   coordT   furthestdist;/* distance to furthest point of outsideset */
 #endif
 #if qh_MAXoutside
   coordT   maxoutside;  /* max computed distance of point to facet
                         Before QHULLfinished this is an approximation
                         since maxdist not always set for mergefacet
                         Actual outer plane is +DISTround and
                         computed outer plane is +2*DISTround */
 #endif
   coordT   offset;      /* exact offset of hyperplane from origin */
   coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
                         /*   if tricoplanar, shared with a neighbor */
   union {               /* in order of testing */
    realT   area;        /* area of facet, only in io_r.c if  ->isarea */
    facetT *replace;     /*  replacement facet if ->visible and NEWfacets
                              is NULL only if qh_mergedegen_redundant or interior */
    facetT *samecycle;   /*  cycle of facets from the same visible/horizon intersection,
                              if ->newfacet */
    facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */
    facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
    facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
   }f;
   coordT  *center;      /*  centrum for convexity, qh.CENTERtype == qh_AScentrum */
                         /*  Voronoi center, qh.CENTERtype == qh_ASvoronoi */
                         /*   if tricoplanar, shared with a neighbor */
   facetT  *previous;    /* previous facet in the facet_list */
   facetT  *next;        /* next facet in the facet_list */
   setT    *vertices;    /* vertices for this facet, inverse sorted by ID
                            if simplicial, 1st vertex was apex/furthest */
   setT    *ridges;      /* explicit ridges for nonsimplicial facets.
                            for simplicial facets, neighbors define the ridges */
   setT    *neighbors;   /* neighbors of the facet.  If simplicial, the kth
                            neighbor is opposite the kth vertex, and the first
                            neighbor is the horizon facet for the first vertex*/
   setT    *outsideset;  /* set of points outside this facet
                            if non-empty, last point is furthest
                            if NARROWhull, includes coplanars for partitioning*/
   setT    *coplanarset; /* set of points coplanar with this facet
                            > qh.min_vertex and <= facet->max_outside
                            a point is assigned to the furthest facet
                            if non-empty, last point is furthest away */
   unsigned visitid;     /* visit_id, for visiting all neighbors,
                            all uses are independent */
   unsigned id;          /* unique identifier from qh.facet_id */
   unsigned nummerge:9;  /* number of merges */
 #define qh_MAXnummerge 511 /*     2^9-1, 32 flags total, see "flags:" in io_r.c */
   flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
                           /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
                           /*   all tricoplanars share the same apex */
                           /*   if ->degenerate, does not span facet (one logical ridge) */
                           /*   one tricoplanar has ->keepcentrum and ->coplanarset */
                           /*   during qh_triangulate, f.trivisible points to original facet */
   flagT    newfacet:1;  /* True if facet on qh.newfacet_list (new or merged) */
   flagT    visible:1;   /* True if visible facet (will be deleted) */
   flagT    toporient:1; /* True if created with top orientation
                            after merging, use ridge orientation */
   flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
   flagT    seen:1;      /* used to perform operations only once, like visitid */
   flagT    seen2:1;     /* used to perform operations only once, like visitid */
   flagT    flipped:1;   /* True if facet is flipped */
   flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
   flagT    notfurthest:1; /* True if last point of outsideset is not furthest*/
 
 /*-------- flags primarily for output ---------*/
   flagT    good:1;      /* True if a facet marked good for output */
   flagT    isarea:1;    /* True if facet->f.area is defined */
 
 /*-------- flags for merging ------------------*/
   flagT    dupridge:1;  /* True if duplicate ridge in facet */
   flagT    mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge
                             ->normal defined (also defined for mergeridge2) */
   flagT    mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (qhT *qh, mark_dupridges */
   flagT    coplanar:1;  /* True if horizon facet is coplanar at last use */
   flagT     mergehorizon:1; /* True if will merge into horizon (->coplanar) */
   flagT     cycledone:1;/* True if mergecycle_all already done */
   flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
   flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */
   flagT    newmerge:1;  /* True if facet is newly merged for reducevertices */
   flagT    degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
   flagT    redundant:1;  /* True if facet is redundant (degen_mergeset) */
 };
 
 
 /*----------------------------------
 
   ridgeT
     defines a ridge
 
   notes:
   a ridge is hull_dim-1 simplex between two neighboring facets.  If the
   facets are non-simplicial, there may be more than one ridge between
   two facets.  E.G. a 4-d hypercube has two triangles between each pair
   of neighboring facets.
 
   topological information:
     vertices            a set of vertices
     top,bottom          neighboring facets with orientation
 
   geometric information:
     tested              True if ridge is clearly convex
     nonconvex           True if ridge is non-convex
 */
 struct ridgeT {
   setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID
                            NULL if a degen ridge (matchsame) */
   facetT  *top;         /* top facet this ridge is part of */
   facetT  *bottom;      /* bottom facet this ridge is part of */
   unsigned id:24;       /* unique identifier, =>room for 8 flags, bit field matches qh->ridge_id */
   flagT    seen:1;      /* used to perform operations only once */
   flagT    tested:1;    /* True when ridge is tested for convexity */
   flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
                            only one ridge between neighbors may have nonconvex */
 };
 
 /*----------------------------------
 
   vertexT
      defines a vertex
 
   topological information:
     next,previous       doubly-linked list of all vertices
     neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
 
   geometric information:
     point               array of DIM3 coordinates
 */
 struct vertexT {
   vertexT *next;        /* next vertex in vertex_list */
   vertexT *previous;    /* previous vertex in vertex_list */
   pointT  *point;       /* hull_dim coordinates (coordT) */
   setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
                            inits in io_r.c or after first merge */
   unsigned visitid:31;  /* for use with qh.vertex_visit, size must match */
   flagT    seen2:1;     /* another seen flag */
   unsigned id:28;       /* unique identifier, bit field matches qh.vertex_id */
                         /* =>room for 4 flags */
   flagT    seen:1;      /* used to perform operations only once */
   flagT    delridge:1;  /* vertex was part of a deleted ridge */
   flagT    deleted:1;   /* true if vertex on qh.del_vertices */
   flagT    newlist:1;   /* true if vertex on qh.newvertex_list */
 };
 
 /*======= -global variables -qh ============================*/
 
 /*----------------------------------
 
   qhT
    All global variables for qhull are in qhT.  It includes qhmemT, qhstatT, and rbox globals
 
    This version of Qhull is reentrant, but it is not thread-safe.  
    
    Do not run separate threads on the same instance of qhT.
 */
 
 struct qhT {
 
 /*----------------------------------
 
   qh constants
     configuration flags and constants for Qhull
 
   notes:
     The user configures Qhull by defining flags.  They are
     copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
 */
   boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
   boolT ANGLEmerge;       /* true 'Qa' if sort potential merges by angle */
   boolT APPROXhull;       /* true 'Wn' if MINoutside set */
   realT   MINoutside;     /*   'Wn' min. distance for an outside point */
   boolT ANNOTATEoutput;   /* true 'Ta' if annotate output with message codes */
   boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
                              for improving precision in Delaunay triangulations */
   boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
   boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
   boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
   boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
   boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
   realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
   realT postmerge_cos;    /*   'An'    cos_max when post merging */
   boolT DELAUNAY;         /* true 'd' if computing DELAUNAY triangulation */
   boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
   int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
   boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
   int   GOODpoint;        /* 1+n for 'QGn', good facet if visible/not(-) from point n*/
   pointT *GOODpointp;     /*   the actual point */
   boolT GOODthreshold;    /* true if qh.lower_threshold/upper_threshold defined
                              false if qh.SPLITthreshold */
   int   GOODvertex;       /* 1+n, good facet if vertex for point n */
   pointT *GOODvertexp;     /*   the actual point */
   boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
   boolT ISqhullQh;        /* Set by Qhull.cpp on initialization */
   int   IStracing;        /* trace execution, 0=none, 1=least, 4=most, -1=events */
   int   KEEParea;         /* 'PAn' number of largest facets to keep */
   boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
   boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
                               set automatically if 'd Qc' */
   int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
   realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
   realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
   boolT MERGEexact;       /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */
   boolT MERGEindependent; /* true 'Q2' if merging independent sets */
   boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
   realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
   realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
   boolT MERGEvertices;    /* true 'Q3' if merging redundant vertices */
   realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
   boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
   boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning */
   boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
   boolT ONLYgood;         /* true 'Qg' if process points with good visible or horizon facets */
   boolT ONLYmax;          /* true 'Qm' if only process points that increase max_outside */
   boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
   boolT POSTmerge;        /* true if merging after buildhull (Cn or An) */
   boolT PREmerge;         /* true if merging during buildhull (C-n or A-n) */
                         /* NOTE: some of these names are similar to qh_PRINT names */
   boolT PRINTcentrums;    /* true 'Gc' if printing centrums */
   boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
   int   PRINTdim;         /* print dimension for Geomview output */
   boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
   boolT PRINTgood;        /* true 'Pg' if printing good facets */
   boolT PRINTinner;       /* true 'Gi' if printing inner planes */
   boolT PRINTneighbors;   /* true 'PG' if printing neighbors of good facets */
   boolT PRINTnoplanes;    /* true 'Gn' if printing no planes */
   boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
   boolT PRINTouter;       /* true 'Go' if printing outer planes */
   boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
   qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
   boolT PRINTridges;      /* true 'Gr' if print ridges */
   boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
   boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
   boolT PRINTsummary;     /* true 's' if printing summary to stderr */
   boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
   boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
                              need projectinput() for Delaunay in qh_init_B */
   int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
   boolT QUICKhelp;        /* true if quick help message for degen input */
   boolT RANDOMdist;       /* true if randomly change distplane and setfacetplane */
   realT RANDOMfactor;     /*    maximum random perturbation */
   realT RANDOMa;          /*    qh_randomfactor is randr * RANDOMa + RANDOMb */
   realT RANDOMb;
   boolT RANDOMoutside;    /* true if select a random outside point */
   int   REPORTfreq;       /* buildtracing reports every n facets */
   int   REPORTfreq2;      /* tracemerging reports every REPORTfreq/2 facets */
   int   RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
   int   ROTATErandom;     /* 'QRn' seed, 0 time, >= rotate input */
   boolT SCALEinput;       /* true 'Qbk' if scaling input */
   boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
   boolT SETroundoff;      /* true 'E' if qh.DISTround is predefined */
   boolT SKIPcheckmax;     /* true 'Q5' if skip qh_check_maxout */
   boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
   boolT SPLITthresholds;  /* true if upper_/lower_threshold defines a region
                                used only for printing (!for qh.ONLYgood) */
   int   STOPcone;         /* 'TCn' 1+n for stopping after cone for point n */
                           /*       also used by qh_build_withresart for err exit*/
   int   STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
                                         adding point n */
   int   TESTpoints;       /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
   boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
   int   TRACElevel;       /* 'Tn' conditional IStracing level */
   int   TRACElastrun;     /*  qh.TRACElevel applies to last qh.RERUN */
   int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex */
   realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
   int   TRACEmerge;       /* 'TMn' start tracing before this merge */
   boolT TRIangulate;      /* true 'Qt' if triangulate non-simplicial facets */
   boolT TRInormals;       /* true 'Q11' if triangulate duplicates normals (sets Qt) */
   boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
   boolT USEstdout;        /* true 'Tz' if using stdout instead of stderr */
   boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
   boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
   boolT VORONOI;          /* true 'v' if computing Voronoi diagram */
 
   /*--------input constants ---------*/
   realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
   boolT DOcheckmax;       /* true if calling qh_check_maxout (qhT *qh, qh_initqhull_globals) */
   char  *feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
   coordT *feasible_point;  /*    as coordinates, both malloc'd */
   boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io_r.c */
   boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
   int   hull_dim;         /* dimension of hull, set by initbuffers */
   int   input_dim;        /* dimension of input, set by initbuffers */
   int   num_points;       /* number of input points */
   pointT *first_point;    /* array of input points, see POINTSmalloc */
   boolT POINTSmalloc;     /*   true if qh.first_point/num_points allocated */
   pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
   boolT input_malloc;     /* true if qh.input_points malloc'd */
   char  qhull_command[256];/* command line that invoked this program */
   int   qhull_commandsiz2; /*    size of qhull_command at qh_clear_outputflags */
   char  rbox_command[256]; /* command line that produced the input points */
   char  qhull_options[512];/* descriptive list of options */
   int   qhull_optionlen;  /*    length of last line */
   int   qhull_optionsiz;  /*    size of qhull_options at qh_build_withrestart */
   int   qhull_optionsiz2; /*    size of qhull_options at qh_clear_outputflags */
   int   run_id;           /* non-zero, random identifier for this instance of qhull */
   boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
   boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx'.  sets ZEROall_ok */
   realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
                              must set either GOODthreshold or SPLITthreshold
                              if Delaunay, default is 0.0 for upper envelope */
   realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
   realT *upper_bound;     /* scale point[k] to new upper bound */
   realT *lower_bound;     /* scale point[k] to new lower bound
                              project if both upper_ and lower_bound == 0 */
 
 /*----------------------------------
 
   qh precision constants
     precision constants for Qhull
 
   notes:
     qh_detroundoff(qh) computes the maximum roundoff error for distance
     and other computations.  It also sets default values for the
     qh constants above.
 */
   realT ANGLEround;       /* max round off error for angles */
   realT centrum_radius;   /* max centrum radius for convexity (roundoff added) */
   realT cos_max;          /* max cosine for convexity (roundoff added) */
   realT DISTround;        /* max round off error for distances, 'E' overrides qh_distround() */
   realT MAXabs_coord;     /* max absolute coordinate */
   realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
   realT MAXsumcoord;      /* max sum of coordinates */
   realT MAXwidth;         /* max rectilinear width of point coordinates */
   realT MINdenom_1;       /* min. abs. value for 1/x */
   realT MINdenom;         /*    use divzero if denominator < MINdenom */
   realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
   realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
   realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
   boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
   realT *NEARzero;        /* hull_dim array for near zero in gausselim */
   realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
   realT ONEmerge;         /* max distance for merging simplicial facets */
   realT outside_err;      /* application's epsilon for coplanar points
                              qh_check_bestdist() qh_check_points() reports error if point outside */
   realT WIDEfacet;        /* size of wide facet for skipping ridge in
                              area computation and locking centrum */
 
 /*----------------------------------
 
   qh internal constants
     internal constants for Qhull
 */
   char qhull[sizeof("qhull")]; /* "qhull" for checking ownership while debugging */
   jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() and NOerrexit */
   char jmpXtra[40];       /* extra bytes in case jmp_buf is defined wrong by compiler */
   jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() and ALLOWrestart */
   char jmpXtra2[40];      /* extra bytes in case jmp_buf is defined wrong by compiler*/
   FILE *fin;              /* pointer to input file, init by qh_initqhull_start */
   FILE *fout;             /* pointer to output file */
   FILE *ferr;             /* pointer to error file */
   pointT *interior_point; /* center point of the initial simplex*/
   int normal_size;     /* size in bytes for facet normals and point coords*/
   int center_size;     /* size in bytes for Voronoi centers */
   int   TEMPsize;         /* size for small, temporary sets (in quick mem) */
 
 /*----------------------------------
 
   qh facet and vertex lists
     defines lists of facets, new facets, visible facets, vertices, and
     new vertices.  Includes counts, next ids, and trace ids.
   see:
     qh_resetlists()
 */
   facetT *facet_list;     /* first facet */
   facetT  *facet_tail;     /* end of facet_list (dummy facet) */
   facetT *facet_next;     /* next facet for buildhull()
                              previous facets do not have outside sets
                              NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
   facetT *newfacet_list;  /* list of new facets to end of facet_list */
   facetT *visible_list;   /* list of visible facets preceeding newfacet_list,
                              facet->visible set */
   int       num_visible;  /* current number of visible facets */
   unsigned tracefacet_id;  /* set at init, then can print whenever */
   facetT *tracefacet;     /*   set in newfacet/mergefacet, undone in delfacet*/
   unsigned tracevertex_id;  /* set at buildtracing, can print whenever */
   vertexT *tracevertex;     /*   set in newvertex, undone in delvertex*/
   vertexT *vertex_list;     /* list of all vertices, to vertex_tail */
   vertexT  *vertex_tail;    /*      end of vertex_list (dummy vertex) */
   vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
                              all vertices have 'newlist' set */
   int   num_facets;       /* number of facets in facet_list
                              includes visble faces (num_visible) */
   int   num_vertices;     /* number of vertices in facet_list */
   int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
                                includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
   int   num_good;         /* number of good facets (after findgood_all) */
   unsigned facet_id;      /* ID of next, new facet from newfacet() */
   unsigned ridge_id:24;   /* ID of next, new ridge from newridge() */
   unsigned vertex_id:24;  /* ID of next, new vertex from newvertex() */
 
 /*----------------------------------
 
   qh global variables
     defines minimum and maximum distances, next visit ids, several flags,
     and other global variables.
     initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
 */
   unsigned long hulltime; /* ignore time to set up input and randomize */
                           /*   use unsigned to avoid wrap-around errors */
   boolT ALLOWrestart;     /* true if qh_precision can use qh.restartexit */
   int   build_cnt;        /* number of calls to qh_initbuild */
   qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
   int   furthest_id;      /* pointid of furthest point, for tracing */
   facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
   boolT hasAreaVolume;    /* true if totarea, totvol was defined by qh_getarea */
   boolT hasTriangulation; /* true if triangulation created by qh_triangulate */
   realT JOGGLEmax;        /* set 'QJn' if randomly joggle input */
   boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
   realT max_outside;      /* maximum distance from a point to a facet,
                                before roundoff, not simplicial vertices
                                actual outer plane is +DISTround and
                                computed outer plane is +2*DISTround */
   realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
                                before roundoff, due to a merge */
   realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
                                before roundoff, due to a merge
                                if qh.JOGGLEmax, qh_makenewplanes sets it
                                recomputed if qh.DOcheckmax, default -qh.DISTround */
   boolT NEWfacets;        /* true while visible facets invalid due to new or merge
                               from makecone/attachnewfacets to deletevisible */
   boolT findbestnew;      /* true if partitioning calls qh_findbestnew */
   boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
   boolT NOerrexit;        /* true if qh.errexit is not available */
   realT PRINTcradius;     /* radius for printing centrums */
   realT PRINTradius;      /* radius for printing vertex spheres and points */
   boolT POSTmerging;      /* true when post merging */
   int   printoutvar;      /* temporary variable for qh_printbegin, etc. */
   int   printoutnum;      /* number of facets printed */
   boolT QHULLfinished;    /* True after qhull() is finished */
   realT totarea;          /* 'FA': total facet area computed by qh_getarea, hasAreaVolume */
   realT totvol;           /* 'FA': total volume computed by qh_getarea, hasAreaVolume */
   unsigned int visit_id;  /* unique ID for searching neighborhoods, */
   unsigned int vertex_visit:31; /* unique ID for searching vertices, reset with qh_buildtracing */
   boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
   boolT WAScoplanar;      /* True if qh_partitioncoplanar (qhT *qh, qh_check_maxout) */
 
 /*----------------------------------
 
   qh global sets
     defines sets for merging, initial simplex, hashing, extra input points,
     and deleted vertices
 */
   setT *facet_mergeset;   /* temporary set of merges to be done */
   setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
   setT *hash_table;       /* hash table for matching ridges in qh_matchfacets
                              size is setsize() */
   setT *other_points;     /* additional points */
   setT *del_vertices;     /* vertices to partition and delete with visible
                              facets.  Have deleted set for checkfacet */
 
 /*----------------------------------
 
   qh global buffers
     defines buffers for maxtrix operations, input, and error messages
 */
   coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom_r.c */
   coordT **gm_row;        /* array of gm_matrix rows */
   char* line;             /* malloc'd input line of maxline+1 chars */
   int maxline;
   coordT *half_space;     /* malloc'd input array for halfspace (qh.normal_size+coordT) */
   coordT *temp_malloc;    /* malloc'd input array for points */
 
 /*----------------------------------
 
   qh static variables
     defines static variables for individual functions
 
   notes:
     do not use 'static' within a function.  Multiple instances of qhull
     may exist.
 
     do not assume zero initialization, 'QPn' may cause a restart
 */
   boolT ERREXITcalled;    /* true during qh_errexit (qhT *qh, prevents duplicate calls */
   boolT firstcentrum;     /* for qh_printcentrum */
   boolT old_randomdist;   /* save RANDOMdist flag during io, tracing, or statistics */
   setT *coplanarfacetset;  /* set of coplanar facets for searching qh_findbesthorizon() */
   realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
   realT last_high;
   realT last_newhigh;
   unsigned lastreport;    /* for qh_buildtracing */
   int mergereport;        /* for qh_tracemerging */
   setT *old_tempstack;    /* for saving qh->qhmem.tempstack in save_qhull */
   int   ridgeoutnum;      /* number of ridges for 4OFF output (qh_printbegin,etc) */
 
 /*----------------------------------
 
   qh memory management, rbox globals, and statistics
 
   Replaces global data structures defined for libqhull
 */
   int     last_random;    /* Last random number from qh_rand (random_r.c) */
   jmp_buf rbox_errexit;   /* errexit from rboxlib_r.c, for qh_rboxpoints only */
   char    jmpXtra3[40];   /* extra bytes in case jmp_buf is defined wrong by compiler */
   int     rbox_isinteger;
   double  rbox_out_offset;
   void *  cpp_object;     /* C++ pointer.  Currently used by RboxPoints.qh_fprintf_rbox */
 
   /* Last, otherwise zero'd by qh_initqhull_start2 (global_r.c */
   qhmemT  qhmem;          /* Qhull managed memory (mem_r.h) */
   /* After qhmem because its size depends on the number of statistics */
   qhstatT qhstat;         /* Qhull statistics (stat_r.h) */
 };
 
 /*=========== -macros- =========================*/
 
 /*----------------------------------
 
   otherfacet_(ridge, facet)
     return neighboring facet for a ridge in facet
 */
 #define otherfacet_(ridge, facet) \
                         (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
 
 /*----------------------------------
 
   getid_(p)
     return int ID for facet, ridge, or vertex
     return -1 if NULL
 */
 #define getid_(p)       ((p) ? (int)((p)->id) : -1)
 
 /*============== FORALL macros ===================*/
 
 /*----------------------------------
 
   FORALLfacets { ... }
     assign 'facet' to each facet in qh.facet_list
 
   notes:
     uses 'facetT *facet;'
     assumes last facet is a sentinel
     assumes qh defined
 
   see:
     FORALLfacet_( facetlist )
 */
 #define FORALLfacets for (facet=qh->facet_list;facet && facet->next;facet=facet->next)
 
 /*----------------------------------
 
   FORALLpoints { ... }
     assign 'point' to each point in qh.first_point, qh.num_points
 
   notes:
     assumes qh defined
 
   declare:
     coordT *point, *pointtemp;
 */
 #define FORALLpoints FORALLpoint_(qh, qh->first_point, qh->num_points)
 
 /*----------------------------------
 
   FORALLpoint_( qh, points, num) { ... }
     assign 'point' to each point in points array of num points
 
   declare:
     coordT *point, *pointtemp;
 */
 #define FORALLpoint_(qh, points, num) for (point= (points), \
       pointtemp= (points)+qh->hull_dim*(num); point < pointtemp; point += qh->hull_dim)
 
 /*----------------------------------
 
   FORALLvertices { ... }
     assign 'vertex' to each vertex in qh.vertex_list
 
   declare:
     vertexT *vertex;
 
   notes:
     assumes qh.vertex_list terminated with a sentinel
     assumes qh defined
 */
 #define FORALLvertices for (vertex=qh->vertex_list;vertex && vertex->next;vertex= vertex->next)
 
 /*----------------------------------
 
   FOREACHfacet_( facets ) { ... }
     assign 'facet' to each facet in facets
 
   declare:
     facetT *facet, **facetp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
 
 /*----------------------------------
 
   FOREACHneighbor_( facet ) { ... }
     assign 'neighbor' to each neighbor in facet->neighbors
 
   FOREACHneighbor_( vertex ) { ... }
     assign 'neighbor' to each neighbor in vertex->neighbors
 
   declare:
     facetT *neighbor, **neighborp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
 
 /*----------------------------------
 
   FOREACHpoint_( points ) { ... }
     assign 'point' to each point in points set
 
   declare:
     pointT *point, **pointp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
 
 /*----------------------------------
 
   FOREACHridge_( ridges ) { ... }
     assign 'ridge' to each ridge in ridges set
 
   declare:
     ridgeT *ridge, **ridgep;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
 
 /*----------------------------------
 
   FOREACHvertex_( vertices ) { ... }
     assign 'vertex' to each vertex in vertices set
 
   declare:
     vertexT *vertex, **vertexp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
 
 /*----------------------------------
 
   FOREACHfacet_i_( qh, facets ) { ... }
     assign 'facet' and 'facet_i' for each facet in facets set
 
   declare:
     facetT *facet;
     int     facet_n, facet_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHfacet_i_(qh, facets)    FOREACHsetelement_i_(qh, facetT, facets, facet)
 
 /*----------------------------------
 
   FOREACHneighbor_i_( qh, facet ) { ... }
     assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
 
   FOREACHneighbor_i_( qh, vertex ) { ... }
     assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors
 
   declare:
     facetT *neighbor;
     int     neighbor_n, neighbor_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHneighbor_i_(qh, facet)  FOREACHsetelement_i_(qh, facetT, facet->neighbors, neighbor)
 
 /*----------------------------------
 
   FOREACHpoint_i_( qh, points ) { ... }
     assign 'point' and 'point_i' for each point in points set
 
   declare:
     pointT *point;
     int     point_n, point_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHpoint_i_(qh, points)    FOREACHsetelement_i_(qh, pointT, points, point)
 
 /*----------------------------------
 
   FOREACHridge_i_( qh, ridges ) { ... }
     assign 'ridge' and 'ridge_i' for each ridge in ridges set
 
   declare:
     ridgeT *ridge;
     int     ridge_n, ridge_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHridge_i_(qh, ridges)    FOREACHsetelement_i_(qh, ridgeT, ridges, ridge)
 
 /*----------------------------------
 
   FOREACHvertex_i_( qh, vertices ) { ... }
     assign 'vertex' and 'vertex_i' for each vertex in vertices set
 
   declare:
     vertexT *vertex;
     int     vertex_n, vertex_i;
 
   see:
     FOREACHsetelement_i_
 */
 #define FOREACHvertex_i_(qh, vertices) FOREACHsetelement_i_(qh, vertexT, vertices,vertex)
 
 /********* -libqhull_r.c prototypes (duplicated from qhull_ra.h) **********************/
 
 void    qh_qhull(qhT *qh);
 boolT   qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist);
 void    qh_printsummary(qhT *qh, FILE *fp);
 
 /********* -user.c prototypes (alphabetical) **********************/
 
 void    qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge);
 void    qh_errprint(qhT *qh, const char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
 int     qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,
                 char *qhull_cmd, FILE *outfile, FILE *errfile);
 void    qh_printfacetlist(qhT *qh, facetT *facetlist, setT *facets, boolT printall);
 void    qh_printhelp_degenerate(qhT *qh, FILE *fp);
 void    qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle);
 void    qh_printhelp_singular(qhT *qh, FILE *fp);
 void    qh_user_memsizes(qhT *qh);
 
 /********* -usermem_r.c prototypes (alphabetical) **********************/
 void    qh_exit(int exitcode);
 void    qh_free(void *mem);
 void   *qh_malloc(size_t size);
 
 /********* -userprintf_r.c and userprintf_rbox_r.c prototypes **********************/
 void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
 void    qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
 
 /***** -geom_r.c/geom2_r.c/random_r.c prototypes (duplicated from geom_r.h, random_r.h) ****************/
 
 facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
                      boolT bestoutside, boolT newfacets, boolT noupper,
                      realT *dist, boolT *isoutside, int *numpart);
 facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
                      realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
 boolT   qh_gram_schmidt(qhT *qh, int dim, realT **rows);
 void    qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
 void    qh_printsummary(qhT *qh, FILE *fp);
 void    qh_projectinput(qhT *qh);
 void    qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **row);
 void    qh_rotateinput(qhT *qh, realT **rows);
 void    qh_scaleinput(qhT *qh);
 void    qh_setdelaunay(qhT *qh, int dim, int count, pointT *points);
 coordT  *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible);
 
 /***** -global_r.c prototypes (alphabetical) ***********************/
 
 unsigned long qh_clock(qhT *qh);
 void    qh_checkflags(qhT *qh, char *command, char *hiddenflags);
 void    qh_clear_outputflags(qhT *qh);
 void    qh_freebuffers(qhT *qh);
 void    qh_freeqhull(qhT *qh, boolT allmem);
 void    qh_init_A(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
 void    qh_init_B(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
 void    qh_init_qhull_command(qhT *qh, int argc, char *argv[]);
 void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
 void    qh_initflags(qhT *qh, char *command);
 void    qh_initqhull_buffers(qhT *qh);
 void    qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
 void    qh_initqhull_mem(qhT *qh);
 void    qh_initqhull_outputflags(qhT *qh);
 void    qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile);
 void    qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile);
 void    qh_initthresholds(qhT *qh, char *command);
 void    qh_option(qhT *qh, const char *option, int *i, realT *r);
 
 /***** -io_r.c prototypes (duplicated from io_r.h) ***********************/
 
 void    qh_dfacet(qhT *qh, unsigned id);
 void    qh_dvertex(qhT *qh, unsigned id);
 void    qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
 void    qh_produce_output(qhT *qh);
 coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc);
 
 
 /********* -mem_r.c prototypes (duplicated from mem_r.h) **********************/
 
 void qh_meminit(qhT *qh, FILE *ferr);
 void qh_memfreeshort(qhT *qh, int *curlong, int *totlong);
 
 /********* -poly_r.c/poly2_r.c prototypes (duplicated from poly_r.h) **********************/
 
 void    qh_check_output(qhT *qh);
 void    qh_check_points(qhT *qh);
 setT   *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets);
 facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
            realT *bestdist, boolT *isoutside);
 vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp);
 pointT *qh_point(qhT *qh, int id);
 setT   *qh_pointfacet(qhT *qh /*qh.facet_list*/);
 int     qh_pointid(qhT *qh, pointT *point);
 setT   *qh_pointvertex(qhT *qh /*qh.facet_list*/);
 void    qh_setvoronoi_all(qhT *qh);
 void    qh_triangulate(qhT *qh /*qh.facet_list*/);
 
 /********* -rboxpoints_r.c prototypes **********************/
 int     qh_rboxpoints(qhT *qh, char* rbox_command);
 void    qh_errexit_rbox(qhT *qh, int exitcode);
 
 /********* -stat_r.c prototypes (duplicated from stat_r.h) **********************/
 
 void    qh_collectstatistics(qhT *qh);
 void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string);
 
 #endif /* qhDEFlibqhull */
diff --git a/src/libqhullr/mem_r.c b/src/libqhullr/mem_r.c
index 23eef56..3419061 100644
--- a/src/libqhullr/mem_r.c
+++ b/src/libqhullr/mem_r.c
@@ -1,530 +1,530 @@
 /*
  ---------------------------------
 
   mem_r.c
     memory management routines for qhull
 
   See libqhull/mem_r.c for a standalone program.
 
   To initialize memory:
 
     qh_meminit(qh, stderr);
     qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
     qh_memsize(qh, (int)sizeof(facetT));
     qh_memsize(qh, (int)sizeof(facetT));
     ...
     qh_memsetup(qh);
 
   To free up all memory buffers:
     qh_memfreeshort(qh, &curlong, &totlong);
 
   if qh_NOmem,
     malloc/free is used instead of mem.c
 
   notes:
     uses Quickfit algorithm (freelists for commonly allocated sizes)
     assumes small sizes for freelists (it discards the tail of memory buffers)
 
   see:
     qh-mem.htm and mem_r.h
     global_r.c (qh_initbuffers) for an example of using mem_r.c
 
-  Copyright (c) 1993-2014 The Geometry Center.
-  $Id: //main/2011/qhull/src/libqhullr/mem_r.c#7 $$Change: 1797 $
-  $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+  Copyright (c) 1993-2015 The Geometry Center.
+  $Id: //main/2011/qhull/src/libqhullr/mem_r.c#8 $$Change: 1810 $
+  $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "mem_r.h"
 #include "libqhull_r.h"
 
 #include 
 #include 
 #include 
 
 #ifndef qh_NOmem
 
 /*============= internal functions ==============*/
 
 static int qh_intcompare(const void *i, const void *j);
 
 /*========== functions in alphabetical order ======== */
 
 /*---------------------------------
 
   qh_intcompare( i, j )
     used by qsort and bsearch to compare two integers
 */
 static int qh_intcompare(const void *i, const void *j) {
   return(*((const int *)i) - *((const int *)j));
 } /* intcompare */
 
 
 /*----------------------------------
 
   qh_memalloc( qh, insize )
     returns object of insize bytes
     qhmem is the global memory structure
 
   returns:
     pointer to allocated memory
     errors if insufficient memory
 
   notes:
     use explicit type conversion to avoid type warnings on some compilers
     actual object may be larger than insize
     use qh_memalloc_() for inline code for quick allocations
     logs allocations if 'T5'
 
   design:
     if size < qh->qhmem.LASTsize
       if qh->qhmem.freelists[size] non-empty
         return first object on freelist
       else
         round up request to size of qh->qhmem.freelists[size]
         allocate new allocation buffer if necessary
         allocate object from allocation buffer
     else
       allocate object with qh_malloc() in user.c
 */
 void *qh_memalloc(qhT *qh, int insize) {
   void **freelistp, *newbuffer;
   int idx, size, n;
   int outsize, bufsize;
   void *object;
 
   if (insize<0) {
       qh_fprintf(qh, qh->qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d).  Did int overflow due to high-D?\n", insize); /* WARN64 */
       qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
   }
   if (insize>=0 && insize <= qh->qhmem.LASTsize) {
     idx= qh->qhmem.indextable[insize];
     outsize= qh->qhmem.sizetable[idx];
     qh->qhmem.totshort += outsize;
     freelistp= qh->qhmem.freelists+idx;
     if ((object= *freelistp)) {
       qh->qhmem.cntquick++;
       qh->qhmem.totfree -= outsize;
       *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
 #ifdef qh_TRACEshort
       n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
       if (qh->qhmem.IStracing >= 5)
           qh_fprintf(qh, qh->qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
 #endif
       return(object);
     }else {
       qh->qhmem.cntshort++;
       if (outsize > qh->qhmem.freesize) {
         qh->qhmem.totdropped += qh->qhmem.freesize;
         if (!qh->qhmem.curbuffer)
           bufsize= qh->qhmem.BUFinit;
         else
           bufsize= qh->qhmem.BUFsize;
         if (!(newbuffer= qh_malloc((size_t)bufsize))) {
           qh_fprintf(qh, qh->qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
           qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
         }
         *((void **)newbuffer)= qh->qhmem.curbuffer;  /* prepend newbuffer to curbuffer
                                                     list */
         qh->qhmem.curbuffer= newbuffer;
         size= (sizeof(void **) + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;
         qh->qhmem.freemem= (void *)((char *)newbuffer+size);
         qh->qhmem.freesize= bufsize - size;
         qh->qhmem.totbuffer += bufsize - size; /* easier to check */
         /* Periodically test totbuffer.  It matches at beginning and exit of every call */
         n = qh->qhmem.totshort + qh->qhmem.totfree + qh->qhmem.totdropped + qh->qhmem.freesize - outsize;
         if (qh->qhmem.totbuffer != n) {
             qh_fprintf(qh, qh->qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qh->qhmem.totbuffer, n);
             qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
         }
       }
       object= qh->qhmem.freemem;
       qh->qhmem.freemem= (void *)((char *)qh->qhmem.freemem + outsize);
       qh->qhmem.freesize -= outsize;
       qh->qhmem.totunused += outsize - insize;
 #ifdef qh_TRACEshort
       n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
       if (qh->qhmem.IStracing >= 5)
           qh_fprintf(qh, qh->qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
 #endif
       return object;
     }
   }else {                     /* long allocation */
     if (!qh->qhmem.indextable) {
       qh_fprintf(qh, qh->qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
       qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
     }
     outsize= insize;
     qh->qhmem.cntlong++;
     qh->qhmem.totlong += outsize;
     if (qh->qhmem.maxlong < qh->qhmem.totlong)
       qh->qhmem.maxlong= qh->qhmem.totlong;
     if (!(object= qh_malloc((size_t)outsize))) {
       qh_fprintf(qh, qh->qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
       qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
     }
     if (qh->qhmem.IStracing >= 5)
       qh_fprintf(qh, qh->qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, outsize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
   }
   return(object);
 } /* memalloc */
 
 
 /*----------------------------------
 
   qh_memfree(qh, object, insize )
     free up an object of size bytes
     size is insize from qh_memalloc
 
   notes:
     object may be NULL
     type checking warns if using (void **)object
     use qh_memfree_() for quick free's of small objects
 
   design:
     if size <= qh->qhmem.LASTsize
       append object to corresponding freelist
     else
       call qh_free(object)
 */
 void qh_memfree(qhT *qh, void *object, int insize) {
   void **freelistp;
   int idx, outsize;
 
   if (!object)
     return;
   if (insize <= qh->qhmem.LASTsize) {
     qh->qhmem.freeshort++;
     idx= qh->qhmem.indextable[insize];
     outsize= qh->qhmem.sizetable[idx];
     qh->qhmem.totfree += outsize;
     qh->qhmem.totshort -= outsize;
     freelistp= qh->qhmem.freelists + idx;
     *((void **)object)= *freelistp;
     *freelistp= object;
 #ifdef qh_TRACEshort
     idx= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
     if (qh->qhmem.IStracing >= 5)
         qh_fprintf(qh, qh->qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
 #endif
   }else {
     qh->qhmem.freelong++;
     qh->qhmem.totlong -= insize;
     qh_free(object);
     if (qh->qhmem.IStracing >= 5)
       qh_fprintf(qh, qh->qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
   }
 } /* memfree */
 
 
 /*---------------------------------
 
   qh_memfreeshort(qh, curlong, totlong )
     frees up all short and qhmem memory allocations
 
   returns:
     number and size of current long allocations
 
   see:
     qh_freeqhull(qh, allMem)
     qh_memtotal(qh, curlong, totlong, curshort, totshort, maxlong, totbuffer);
 */
 void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {
   void *buffer, *nextbuffer;
   FILE *ferr;
 
   *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
   *totlong= qh->qhmem.totlong;
   for (buffer= qh->qhmem.curbuffer; buffer; buffer= nextbuffer) {
     nextbuffer= *((void **) buffer);
     qh_free(buffer);
   }
   qh->qhmem.curbuffer= NULL;
   if (qh->qhmem.LASTsize) {
     qh_free(qh->qhmem.indextable);
     qh_free(qh->qhmem.freelists);
     qh_free(qh->qhmem.sizetable);
   }
   ferr= qh->qhmem.ferr;
   memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
   qh->qhmem.ferr= ferr;
 } /* memfreeshort */
 
 
 /*----------------------------------
 
   qh_meminit(qh, ferr )
     initialize qhmem and test sizeof( void*)
     Does not throw errors.  qh_exit on failure
 */
 void qh_meminit(qhT *qh, FILE *ferr) {
 
   memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
   if (ferr)
       qh->qhmem.ferr= ferr;
   else
       qh->qhmem.ferr= stderr;
   if (sizeof(void*) < sizeof(int)) {
     qh_fprintf(qh, qh->qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
     qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
   }
   if (sizeof(void*) > sizeof(ptr_intT)) {
       qh_fprintf(qh, qh->qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
       qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
   }
 } /* meminit */
 
 /*---------------------------------
 
   qh_meminitbuffers(qh, tracelevel, alignment, numsizes, bufsize, bufinit )
     initialize qhmem
     if tracelevel >= 5, trace memory allocations
     alignment= desired address alignment for memory allocations
     numsizes= number of freelists
     bufsize=  size of additional memory buffers for short allocations
     bufinit=  size of initial memory buffer for short allocations
 */
 void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
 
   qh->qhmem.IStracing= tracelevel;
   qh->qhmem.NUMsizes= numsizes;
   qh->qhmem.BUFsize= bufsize;
   qh->qhmem.BUFinit= bufinit;
   qh->qhmem.ALIGNmask= alignment-1;
   if (qh->qhmem.ALIGNmask & ~qh->qhmem.ALIGNmask) {
     qh_fprintf(qh, qh->qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   qh->qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
   qh->qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
   if (!qh->qhmem.sizetable || !qh->qhmem.freelists) {
     qh_fprintf(qh, qh->qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
     qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
   }
   if (qh->qhmem.IStracing >= 1)
     qh_fprintf(qh, qh->qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
 } /* meminitbuffers */
 
 /*---------------------------------
 
   qh_memsetup(qh)
     set up memory after running memsize()
 */
 void qh_memsetup(qhT *qh) {
   int k,i;
 
   qsort(qh->qhmem.sizetable, (size_t)qh->qhmem.TABLEsize, sizeof(int), qh_intcompare);
   qh->qhmem.LASTsize= qh->qhmem.sizetable[qh->qhmem.TABLEsize-1];
   if(qh->qhmem.LASTsize >= qh->qhmem.BUFsize || qh->qhmem.LASTsize >= qh->qhmem.BUFinit) {
     qh_fprintf(qh, qh->qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
             qh->qhmem.LASTsize, qh->qhmem.BUFsize, qh->qhmem.BUFinit);
     qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
   }
   if (!(qh->qhmem.indextable= (int *)qh_malloc((qh->qhmem.LASTsize+1) * sizeof(int)))) {
     qh_fprintf(qh, qh->qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
     qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
   }
   for (k=qh->qhmem.LASTsize+1; k--; )
     qh->qhmem.indextable[k]= k;
   i= 0;
   for (k=0; k <= qh->qhmem.LASTsize; k++) {
     if (qh->qhmem.indextable[k] <= qh->qhmem.sizetable[i])
       qh->qhmem.indextable[k]= i;
     else
       qh->qhmem.indextable[k]= ++i;
   }
 } /* memsetup */
 
 /*---------------------------------
 
   qh_memsize(qh, size )
     define a free list for this size
 */
 void qh_memsize(qhT *qh, int size) {
   int k;
 
   if(qh->qhmem.LASTsize) {
     qh_fprintf(qh, qh->qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n");
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   size= (size + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;
   for (k=qh->qhmem.TABLEsize; k--; ) {
     if (qh->qhmem.sizetable[k] == size)
       return;
   }
   if (qh->qhmem.TABLEsize < qh->qhmem.NUMsizes)
     qh->qhmem.sizetable[qh->qhmem.TABLEsize++]= size;
   else
     qh_fprintf(qh, qh->qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qh->qhmem.NUMsizes);
 } /* memsize */
 
 
 /*---------------------------------
 
   qh_memstatistics(qh, fp )
     print out memory statistics
 
     Verifies that qh->qhmem.totfree == sum of freelists
 */
 void qh_memstatistics(qhT *qh, FILE *fp) {
   int i, count, totfree= 0;
   void *object;
 
   for (i=0; i < qh->qhmem.TABLEsize; i++) {
     count=0;
     for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))
       count++;
     totfree += qh->qhmem.sizetable[i] * count;
   }
   if (totfree != qh->qhmem.totfree) {
       qh_fprintf(qh, qh->qhmem.ferr, 6211, "qh_memstatistics internal error: totfree %d not equal to freelist total %d\n", qh->qhmem.totfree, totfree);
       qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   qh_fprintf(qh, fp, 9278, "\nmemory statistics:\n\
 %7d quick allocations\n\
 %7d short allocations\n\
 %7d long allocations\n\
 %7d short frees\n\
 %7d long frees\n\
 %7d bytes of short memory in use\n\
 %7d bytes of short memory in freelists\n\
 %7d bytes of dropped short memory\n\
 %7d bytes of unused short memory (estimated)\n\
 %7d bytes of long memory allocated (max, except for input)\n\
 %7d bytes of long memory in use (in %d pieces)\n\
 %7d bytes of short memory buffers (minus links)\n\
 %7d bytes per short memory buffer (initially %d bytes)\n",
            qh->qhmem.cntquick, qh->qhmem.cntshort, qh->qhmem.cntlong,
            qh->qhmem.freeshort, qh->qhmem.freelong,
            qh->qhmem.totshort, qh->qhmem.totfree,
            qh->qhmem.totdropped + qh->qhmem.freesize, qh->qhmem.totunused,
            qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong,
            qh->qhmem.totbuffer, qh->qhmem.BUFsize, qh->qhmem.BUFinit);
   if (qh->qhmem.cntlarger) {
     qh_fprintf(qh, fp, 9279, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
            qh->qhmem.cntlarger, ((float)qh->qhmem.totlarger)/(float)qh->qhmem.cntlarger);
     qh_fprintf(qh, fp, 9280, "  freelists(bytes->count):");
   }
   for (i=0; i < qh->qhmem.TABLEsize; i++) {
     count=0;
     for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))
       count++;
     qh_fprintf(qh, fp, 9281, " %d->%d", qh->qhmem.sizetable[i], count);
   }
   qh_fprintf(qh, fp, 9282, "\n\n");
 } /* memstatistics */
 
 
 /*---------------------------------
 
   qh_NOmem
     turn off quick-fit memory allocation
 
   notes:
     uses qh_malloc() and qh_free() instead
 */
 #else /* qh_NOmem */
 
 void *qh_memalloc(qhT *qh, int insize) {
   void *object;
 
   if (!(object= qh_malloc((size_t)insize))) {
     qh_fprintf(qh, qh->qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
     qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
   }
   qh->qhmem.cntlong++;
   qh->qhmem.totlong += insize;
   if (qh->qhmem.maxlong < qh->qhmem.totlong)
       qh->qhmem.maxlong= qh->qhmem.totlong;
   if (qh->qhmem.IStracing >= 5)
     qh_fprintf(qh, qh->qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
   return object;
 }
 
 void qh_memfree(qhT *qh, void *object, int insize) {
 
   if (!object)
     return;
   qh_free(object);
   qh->qhmem.freelong++;
   qh->qhmem.totlong -= insize;
   if (qh->qhmem.IStracing >= 5)
     qh_fprintf(qh, qh->qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
 }
 
 void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {
   *totlong= qh->qhmem.totlong;
   *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
   memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
 }
 
 void qh_meminit(qhT *qh, FILE *ferr) {
 
   memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
   if (ferr)
       qh->qhmem.ferr= ferr;
   else
       qh->qhmem.ferr= stderr;
   if (sizeof(void*) < sizeof(int)) {
     qh_fprintf(qh, qh->qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
 }
 
 void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
 
   qh->qhmem.IStracing= tracelevel;
 }
 
 void qh_memsetup(qhT *qh) {
 
 }
 
 void qh_memsize(qhT *qh, int size) {
 
 }
 
 void qh_memstatistics(qhT *qh, FILE *fp) {
 
   qh_fprintf(qh, fp, 9409, "\nmemory statistics:\n\
 %7d long allocations\n\
 %7d long frees\n\
 %7d bytes of long memory allocated (max, except for input)\n\
 %7d bytes of long memory in use (in %d pieces)\n",
            qh->qhmem.cntlong,
            qh->qhmem.freelong,
            qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong);
 }
 
 #endif /* qh_NOmem */
 
 /*---------------------------------
 
   qh_memtotal(qh, totlong, curlong, totshort, curshort, maxlong, totbuffer )
     Return the total, allocated long and short memory
 
   returns:
     Returns the total current bytes of long and short allocations
     Returns the current count of long and short allocations
     Returns the maximum long memory and total short buffer (minus one link per buffer)
     Does not error (for deprecated UsingLibQhull.cpp (libqhullpcpp))
 */
 void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
     *totlong= qh->qhmem.totlong;
     *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
     *totshort= qh->qhmem.totshort;
     *curshort= qh->qhmem.cntshort + qh->qhmem.cntquick - qh->qhmem.freeshort;
     *maxlong= qh->qhmem.maxlong;
     *totbuffer= qh->qhmem.totbuffer;
 } /* memtotlong */
 
diff --git a/src/libqhullr/mem_r.h b/src/libqhullr/mem_r.h
index 5e88985..e6aff30 100644
--- a/src/libqhullr/mem_r.h
+++ b/src/libqhullr/mem_r.h
@@ -1,223 +1,223 @@
 /*
  ---------------------------------
 
    mem_r.h
      prototypes for memory management functions
 
    see qh-mem.htm, mem_r.c and qset_r.h
 
    for error handling, writes message and calls
      qh_errexit(qhT *qh, qhmem_ERRmem, NULL, NULL) if insufficient memory
        and
      qh_errexit(qhT *qh, qhmem_ERRqhull, NULL, NULL) otherwise
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/mem_r.h#4 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/mem_r.h#5 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFmem
 #define qhDEFmem 1
 
 #include 
 
 #ifndef DEFsetT
 #define DEFsetT 1
 typedef struct setT setT;          /* defined in qset_r.h */
 #endif
 
 #ifndef DEFqhT
 #define DEFqhT 1
 typedef struct qhT qhT;          /* defined in libqhull_r.h */
 #endif
 
 /*---------------------------------
 
   qh_NOmem
     turn off quick-fit memory allocation
 
   notes:
     mem_r.c implements Quickfit memory allocation for about 20% time
     savings.  If it fails on your machine, try to locate the
     problem, and send the answer to qhull@qhull.org.  If this can
     not be done, define qh_NOmem to use malloc/free instead.
 
    #define qh_NOmem
 */
 
 /*---------------------------------
 
 qh_TRACEshort
 Trace short and quick memory allocations at T5
 
 */
 #define qh_TRACEshort
 
 /*-------------------------------------------
     to avoid bus errors, memory allocation must consider alignment requirements.
     malloc() automatically takes care of alignment.   Since mem_r.c manages
     its own memory, we need to explicitly specify alignment in
     qh_meminitbuffers().
 
     A safe choice is sizeof(double).  sizeof(float) may be used if doubles
     do not occur in data structures and pointers are the same size.  Be careful
     of machines (e.g., DEC Alpha) with large pointers.  If gcc is available,
     use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
 
    see qh_MEMalign in user.h for qhull's alignment
 */
 
 #define qhmem_ERRmem 4    /* matches qh_ERRmem in libqhull_r.h */
 #define qhmem_ERRqhull 5  /* matches qh_ERRqhull in libqhull_r.h */
 
 /*----------------------------------
 
   ptr_intT
     for casting a void * to an integer-type that holds a pointer
     Used for integer expressions (e.g., computing qh_gethash() in poly_r.c)
 
   notes:
     WARN64 -- these notes indicate 64-bit issues
     On 64-bit machines, a pointer may be larger than an 'int'.
     qh_meminit()/mem_r.c checks that 'ptr_intT' holds a 'void*'
     ptr_intT is typically a signed value, but not necessarily so
     size_t is typically unsigned, but should match the parameter type
     Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
     This matches Qt convention and is easier to work with.  
 */
 #if _MSC_VER && defined(_WIN64)
 typedef long long ptr_intT;
 #else
 typedef long ptr_intT;
 #endif
 
 /*----------------------------------
 
   qhmemT
     global memory structure for mem_r.c
 
  notes:
    users should ignore qhmem except for writing extensions
    qhmem is allocated in mem_r.c
 
    qhmem could be swapable like qh and qhstat, but then
    multiple qh's and qhmem's would need to keep in synch.
    A swapable qhmem would also waste memory buffers.  As long
    as memory operations are atomic, there is no problem with
    multiple qh structures being active at the same time.
    If you need separate address spaces, you can swap the
    contents of qh->qhmem.
 */
 typedef struct qhmemT qhmemT;
 
 /* Update qhmem in mem_r.c if add or remove fields */
 struct qhmemT {               /* global memory management variables */
   int      BUFsize;           /* size of memory allocation buffer */
   int      BUFinit;           /* initial size of memory allocation buffer */
   int      TABLEsize;         /* actual number of sizes in free list table */
   int      NUMsizes;          /* maximum number of sizes in free list table */
   int      LASTsize;          /* last size in free list table */
   int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
   void   **freelists;          /* free list table, linked by offset 0 */
   int     *sizetable;         /* size of each freelist */
   int     *indextable;        /* size->index table */
   void    *curbuffer;         /* current buffer, linked by offset 0 */
   void    *freemem;           /*   free memory in curbuffer */
   int      freesize;          /*   size of freemem in bytes */
   setT    *tempstack;         /* stack of temporary memory, managed by users */
   FILE    *ferr;              /* file for reporting errors when 'qh' may be undefined */
   int      IStracing;         /* =5 if tracing memory allocations */
   int      cntquick;          /* count of quick allocations */
                               /* Note: removing statistics doesn't effect speed */
   int      cntshort;          /* count of short allocations */
   int      cntlong;           /* count of long allocations */
   int      freeshort;         /* count of short memfrees */
   int      freelong;          /* count of long memfrees */
   int      totbuffer;         /* total short memory buffers minus buffer links */
   int      totdropped;        /* total dropped memory at end of short memory buffers (e.g., freesize) */
   int      totfree;           /* total size of free, short memory on freelists */
   int      totlong;           /* total size of long memory in use */
   int      maxlong;           /*   maximum totlong */
   int      totshort;          /* total size of short memory in use */
   int      totunused;         /* total unused short memory (estimated, short size - request size of first allocations) */
   int      cntlarger;         /* count of setlarger's */
   int      totlarger;         /* total copied by setlarger */
 };
 
 
 /*==================== -macros ====================*/
 
 /*----------------------------------
 
   qh_memalloc_(qh, freelistp, insize, object, type)
     returns object of size bytes
         assumes size<=qh->qhmem.LASTsize and void **freelistp is a temp
 */
 
 #if defined qh_NOmem
 #define qh_memalloc_(qh, insize, freelistp, object, type) {\
   object= (type*)qh_memalloc(qh, insize); }
 #elif defined qh_TRACEshort
 #define qh_memalloc_(qh, insize, freelistp, object, type) {\
     freelistp= NULL; /* Avoid warnings */ \
     object= (type*)qh_memalloc(qh, insize); }
 #else /* !qh_NOmem */
 
 #define qh_memalloc_(qh, insize, freelistp, object, type) {\
   freelistp= qh->qhmem.freelists + qh->qhmem.indextable[insize];\
   if ((object= (type*)*freelistp)) {\
     qh->qhmem.totshort += qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
     qh->qhmem.totfree -= qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
     qh->qhmem.cntquick++;  \
     *freelistp= *((void **)*freelistp);\
   }else object= (type*)qh_memalloc(qh, insize);}
 #endif
 
 /*----------------------------------
 
   qh_memfree_(qh, object, insize, freelistp)
     free up an object
 
   notes:
     object may be NULL
     assumes size<=qh->qhmem.LASTsize and void **freelistp is a temp
 */
 #if defined qh_NOmem
 #define qh_memfree_(qh, object, insize, freelistp) {\
   qh_memfree(qh, object, insize); }
 #elif defined qh_TRACEshort
 #define qh_memfree_(qh, object, insize, freelistp) {\
     freelistp= NULL; /* Avoid warnings */ \
     qh_memfree(qh, object, insize); }
 #else /* !qh_NOmem */
 
 #define qh_memfree_(qh, object, insize, freelistp) {\
   if (object) { \
     qh->qhmem.freeshort++;\
     freelistp= qh->qhmem.freelists + qh->qhmem.indextable[insize];\
     qh->qhmem.totshort -= qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
     qh->qhmem.totfree += qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
     *((void **)object)= *freelistp;\
     *freelistp= object;}}
 #endif
 
 /*=============== prototypes in alphabetical order ============*/
 
 void *qh_memalloc(qhT *qh, int insize);
 void qh_memfree(qhT *qh, void *object, int insize);
 void qh_memfreeshort(qhT *qh, int *curlong, int *totlong);
 void qh_meminit(qhT *qh, FILE *ferr);
 void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes,
                         int bufsize, int bufinit);
 void qh_memsetup(qhT *qh);
 void qh_memsize(qhT *qh, int size);
 void qh_memstatistics(qhT *qh, FILE *fp);
 void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer);
 
 #endif /* qhDEFmem */
diff --git a/src/libqhullr/merge_r.c b/src/libqhullr/merge_r.c
index a424e8e..1e1d39d 100644
--- a/src/libqhullr/merge_r.c
+++ b/src/libqhullr/merge_r.c
@@ -1,3623 +1,3623 @@
 /*
  ---------------------------------
 
    merge_r.c
    merges non-convex facets
 
    see qh-merge.htm and merge_r.h
 
    other modules call qh_premerge() and qh_postmerge()
 
    the user may call qh_postmerge() to perform additional merges.
 
    To remove deleted facets and vertices (qhull() in libqhull_r.c):
      qh_partitionvisible(qh, !qh_ALL, &numoutside);  // visible_list, newfacet_list
      qh_deletevisible();         // qh.visible_list
      qh_resetlists(qh, False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list
 
    assumes qh.CENTERtype= centrum
 
    merges occur in qh_mergefacet and in qh_mergecycle
    vertex->neighbors not set until the first merge occurs
 
-   Copyright (c) 1993-2014 C.B. Barber.
-   $Id: //main/2011/qhull/src/libqhullr/merge_r.c#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 C.B. Barber.
+   $Id: //main/2011/qhull/src/libqhullr/merge_r.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_ra.h"
 
 #ifndef qh_NOmerge
 
 /*===== functions(alphabetical after premerge and postmerge) ======*/
 
 /*---------------------------------
 
   qh_premerge(qh, apex, maxcentrum )
     pre-merge nonconvex facets in qh.newfacet_list for apex
     maxcentrum defines coplanar and concave (qh_test_appendmerge)
 
   returns:
     deleted facets added to qh.visible_list with facet->visible set
 
   notes:
     uses globals, qh.MERGEexact, qh.PREmerge
 
   design:
     mark duplicate ridges in qh.newfacet_list
     merge facet cycles in qh.newfacet_list
     merge duplicate ridges and concave facets in qh.newfacet_list
     check merged facet cycles for degenerate and redundant facets
     merge degenerate and redundant facets
     collect coplanar and concave facets
     merge concave, coplanar, degenerate, and redundant facets
 */
 void qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle) {
   boolT othermerge= False;
   facetT *newfacet;
 
   if (qh->ZEROcentrum && qh_checkzero(qh, !qh_ALL))
     return;
   trace2((qh, qh->ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",
             maxcentrum, maxangle, apex->id, getid_(qh->newfacet_list)));
   if (qh->IStracing >= 4 && qh->num_facets < 50)
     qh_printlists(qh);
   qh->centrum_radius= maxcentrum;
   qh->cos_max= maxangle;
   qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);
   qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
   if (qh->hull_dim >=3) {
     qh_mark_dupridges(qh, qh->newfacet_list); /* facet_mergeset */
     qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
     qh_forcedmerges(qh, &othermerge /* qh->facet_mergeset */);
     FORALLnew_facets {  /* test samecycle merges */
       if (!newfacet->simplicial && !newfacet->mergeridge)
         qh_degen_redundant_neighbors(qh, newfacet, NULL);
     }
     if (qh_merge_degenredundant(qh))
       othermerge= True;
   }else /* qh->hull_dim == 2 */
     qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
   qh_flippedmerges(qh, qh->newfacet_list, &othermerge);
   if (!qh->MERGEexact || zzval_(Ztotmerge)) {
     zinc_(Zpremergetot);
     qh->POSTmerging= False;
     qh_getmergeset_initial(qh, qh->newfacet_list);
     qh_all_merges(qh, othermerge, False);
   }
   qh_settempfree(qh, &qh->facet_mergeset);
   qh_settempfree(qh, &qh->degen_mergeset);
 } /* premerge */
 
 /*---------------------------------
 
   qh_postmerge(qh, reason, maxcentrum, maxangle, vneighbors )
     post-merge nonconvex facets as defined by maxcentrum and maxangle
     'reason' is for reporting progress
     if vneighbors,
       calls qh_test_vneighbors at end of qh_all_merge
     if firstmerge,
       calls qh_reducevertices before qh_getmergeset
 
   returns:
     if first call (qh.visible_list != qh.facet_list),
       builds qh.facet_newlist, qh.newvertex_list
     deleted facets added to qh.visible_list with facet->visible
     qh.visible_list == qh.facet_list
 
   notes:
 
 
   design:
     if first call
       set qh.visible_list and qh.newfacet_list to qh.facet_list
       add all facets to qh.newfacet_list
       mark non-simplicial facets, facet->newmerge
       set qh.newvertext_list to qh.vertex_list
       add all vertices to qh.newvertex_list
       if a pre-merge occured
         set vertex->delridge {will retest the ridge}
         if qh.MERGEexact
           call qh_reducevertices()
       if no pre-merging
         merge flipped facets
     determine non-convex facets
     merge all non-convex facets
 */
 void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
                       boolT vneighbors) {
   facetT *newfacet;
   boolT othermerges= False;
   vertexT *vertex;
 
   if (qh->REPORTfreq || qh->IStracing) {
     qh_buildtracing(qh, NULL, NULL);
     qh_printsummary(qh, qh->ferr);
     if (qh->PRINTstatistics)
       qh_printallstatistics(qh, qh->ferr, "reason");
     qh_fprintf(qh, qh->ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",
         reason, maxcentrum, maxangle);
   }
   trace2((qh, qh->ferr, 2009, "qh_postmerge: postmerge.  test vneighbors? %d\n",
             vneighbors));
   qh->centrum_radius= maxcentrum;
   qh->cos_max= maxangle;
   qh->POSTmerging= True;
   qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);
   qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
   if (qh->visible_list != qh->facet_list) {  /* first call */
     qh->NEWfacets= True;
     qh->visible_list= qh->newfacet_list= qh->facet_list;
     FORALLnew_facets {
       newfacet->newfacet= True;
        if (!newfacet->simplicial)
         newfacet->newmerge= True;
      zinc_(Zpostfacets);
     }
     qh->newvertex_list= qh->vertex_list;
     FORALLvertices
       vertex->newlist= True;
     if (qh->VERTEXneighbors) { /* a merge has occurred */
       FORALLvertices
         vertex->delridge= True; /* test for redundant, needed? */
       if (qh->MERGEexact) {
         if (qh->hull_dim <= qh_DIMreduceBuild)
           qh_reducevertices(qh); /* was skipped during pre-merging */
       }
     }
     if (!qh->PREmerge && !qh->MERGEexact)
       qh_flippedmerges(qh, qh->newfacet_list, &othermerges);
   }
   qh_getmergeset_initial(qh, qh->newfacet_list);
   qh_all_merges(qh, False, vneighbors);
   qh_settempfree(qh, &qh->facet_mergeset);
   qh_settempfree(qh, &qh->degen_mergeset);
 } /* post_merge */
 
 /*---------------------------------
 
   qh_all_merges(qh, othermerge, vneighbors )
     merge all non-convex facets
 
     set othermerge if already merged facets (for qh_reducevertices)
     if vneighbors
       tests vertex neighbors for convexity at end
     qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
     qh.degen_mergeset is defined
     if qh.MERGEexact && !qh.POSTmerging,
       does not merge coplanar facets
 
   returns:
     deleted facets added to qh.visible_list with facet->visible
     deleted vertices added qh.delvertex_list with vertex->delvertex
 
   notes:
     unless !qh.MERGEindependent,
       merges facets in independent sets
     uses qh.newfacet_list as argument since merges call qh_removefacet()
 
   design:
     while merges occur
       for each merge in qh.facet_mergeset
         unless one of the facets was already merged in this pass
           merge the facets
         test merged facets for additional merges
         add merges to qh.facet_mergeset
       if vertices record neighboring facets
         rename redundant vertices
           update qh.facet_mergeset
     if vneighbors ??
       tests vertex neighbors for convexity at end
 */
 void qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors) {
   facetT *facet1, *facet2;
   mergeT *merge;
   boolT wasmerge= True, isreduce;
   void **freelistp;  /* used !qh_NOmem */
   vertexT *vertex;
   mergeType mergetype;
   int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;
 
   trace2((qh, qh->ferr, 2010, "qh_all_merges: starting to merge facets beginning from f%d\n",
             getid_(qh->newfacet_list)));
   while (True) {
     wasmerge= False;
     while (qh_setsize(qh, qh->facet_mergeset)) {
       while ((merge= (mergeT*)qh_setdellast(qh->facet_mergeset))) {
         facet1= merge->facet1;
         facet2= merge->facet2;
         mergetype= merge->type;
         qh_memfree_(qh, merge, (int)sizeof(mergeT), freelistp);
         if (facet1->visible || facet2->visible) /*deleted facet*/
           continue;
         if ((facet1->newfacet && !facet1->tested)
                 || (facet2->newfacet && !facet2->tested)) {
           if (qh->MERGEindependent && mergetype <= MRGanglecoplanar)
             continue;      /* perform independent sets of merges */
         }
         qh_merge_nonconvex(qh, facet1, facet2, mergetype);
         numdegenredun += qh_merge_degenredundant(qh);
         numnewmerges++;
         wasmerge= True;
         if (mergetype == MRGconcave)
           numconcave++;
         else /* MRGcoplanar or MRGanglecoplanar */
           numcoplanar++;
       } /* while setdellast */
       if (qh->POSTmerging && qh->hull_dim <= qh_DIMreduceBuild
       && numnewmerges > qh_MAXnewmerges) {
         numnewmerges= 0;
         qh_reducevertices(qh);  /* otherwise large post merges too slow */
       }
       qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */
     } /* while mergeset */
     if (qh->VERTEXneighbors) {
       isreduce= False;
       if (qh->hull_dim >=4 && qh->POSTmerging) {
         FORALLvertices
           vertex->delridge= True;
         isreduce= True;
       }
       if ((wasmerge || othermerge) && (!qh->MERGEexact || qh->POSTmerging)
           && qh->hull_dim <= qh_DIMreduceBuild) {
         othermerge= False;
         isreduce= True;
       }
       if (isreduce) {
         if (qh_reducevertices(qh)) {
           qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */
           continue;
         }
       }
     }
     if (vneighbors && qh_test_vneighbors(qh /* qh->newfacet_list */))
       continue;
     break;
   } /* while (True) */
   if (qh->CHECKfrequently && !qh->MERGEexact) {
     qh->old_randomdist= qh->RANDOMdist;
     qh->RANDOMdist= False;
     qh_checkconvex(qh, qh->newfacet_list, qh_ALGORITHMfault);
     /* qh_checkconnect(qh); [this is slow and it changes the facet order] */
     qh->RANDOMdist= qh->old_randomdist;
   }
   trace1((qh, qh->ferr, 1009, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",
     numcoplanar, numconcave, numdegenredun));
   if (qh->IStracing >= 4 && qh->num_facets < 50)
     qh_printlists(qh);
 } /* all_merges */
 
 
 /*---------------------------------
 
   qh_appendmergeset(qh, facet, neighbor, mergetype, angle )
     appends an entry to qh.facet_mergeset or qh.degen_mergeset
 
     angle ignored if NULL or !qh.ANGLEmerge
 
   returns:
     merge appended to facet_mergeset or degen_mergeset
       sets ->degenerate or ->redundant if degen_mergeset
 
   see:
     qh_test_appendmerge()
 
   design:
     allocate merge entry
     if regular merge
       append to qh.facet_mergeset
     else if degenerate merge and qh.facet_mergeset is all degenerate
       append to qh.degen_mergeset
     else if degenerate merge
       prepend to qh.degen_mergeset
     else if redundant merge
       append to qh.degen_mergeset
 */
 void qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {
   mergeT *merge, *lastmerge;
   void **freelistp; /* used !qh_NOmem */
 
   if (facet->redundant)
     return;
   if (facet->degenerate && mergetype == MRGdegen)
     return;
   qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
   merge->facet1= facet;
   merge->facet2= neighbor;
   merge->type= mergetype;
   if (angle && qh->ANGLEmerge)
     merge->angle= *angle;
   if (mergetype < MRGdegen)
     qh_setappend(qh, &(qh->facet_mergeset), merge);
   else if (mergetype == MRGdegen) {
     facet->degenerate= True;
     if (!(lastmerge= (mergeT*)qh_setlast(qh->degen_mergeset))
     || lastmerge->type == MRGdegen)
       qh_setappend(qh, &(qh->degen_mergeset), merge);
     else
       qh_setaddnth(qh, &(qh->degen_mergeset), 0, merge);
   }else if (mergetype == MRGredundant) {
     facet->redundant= True;
     qh_setappend(qh, &(qh->degen_mergeset), merge);
   }else /* mergetype == MRGmirror */ {
     if (facet->redundant || neighbor->redundant) {
       qh_fprintf(qh, qh->ferr, 6092, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n",
            facet->id, neighbor->id);
       qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
     }
     if (!qh_setequal(facet->vertices, neighbor->vertices)) {
       qh_fprintf(qh, qh->ferr, 6093, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
            facet->id, neighbor->id);
       qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
     }
     facet->redundant= True;
     neighbor->redundant= True;
     qh_setappend(qh, &(qh->degen_mergeset), merge);
   }
 } /* appendmergeset */
 
 
 /*---------------------------------
 
   qh_basevertices(qh, samecycle )
     return temporary set of base vertices for samecycle
     samecycle is first facet in the cycle
     assumes apex is SETfirst_( samecycle->vertices )
 
   returns:
     vertices(settemp)
     all ->seen are cleared
 
   notes:
     uses qh_vertex_visit;
 
   design:
     for each facet in samecycle
       for each unseen vertex in facet->vertices
         append to result
 */
 setT *qh_basevertices(qhT *qh, facetT *samecycle) {
   facetT *same;
   vertexT *apex, *vertex, **vertexp;
   setT *vertices= qh_settemp(qh, qh->TEMPsize);
 
   apex= SETfirstt_(samecycle->vertices, vertexT);
   apex->visitid= ++qh->vertex_visit;
   FORALLsame_cycle_(samecycle) {
     if (same->mergeridge)
       continue;
     FOREACHvertex_(same->vertices) {
       if (vertex->visitid != qh->vertex_visit) {
         qh_setappend(qh, &vertices, vertex);
         vertex->visitid= qh->vertex_visit;
         vertex->seen= False;
       }
     }
   }
   trace4((qh, qh->ferr, 4019, "qh_basevertices: found %d vertices\n",
          qh_setsize(qh, vertices)));
   return vertices;
 } /* basevertices */
 
 /*---------------------------------
 
   qh_checkconnect(qh)
     check that new facets are connected
     new facets are on qh.newfacet_list
 
   notes:
     this is slow and it changes the order of the facets
     uses qh.visit_id
 
   design:
     move first new facet to end of qh.facet_list
     for all newly appended facets
       append unvisited neighbors to end of qh.facet_list
     for all new facets
       report error if unvisited
 */
 void qh_checkconnect(qhT *qh /* qh->newfacet_list */) {
   facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
 
   facet= qh->newfacet_list;
   qh_removefacet(qh, facet);
   qh_appendfacet(qh, facet);
   facet->visitid= ++qh->visit_id;
   FORALLfacet_(facet) {
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh->visit_id) {
         qh_removefacet(qh, neighbor);
         qh_appendfacet(qh, neighbor);
         neighbor->visitid= qh->visit_id;
       }
     }
   }
   FORALLnew_facets {
     if (newfacet->visitid == qh->visit_id)
       break;
     qh_fprintf(qh, qh->ferr, 6094, "qhull error: f%d is not attached to the new facets\n",
          newfacet->id);
     errfacet= newfacet;
   }
   if (errfacet)
     qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
 } /* checkconnect */
 
 /*---------------------------------
 
   qh_checkzero(qh, testall )
     check that facets are clearly convex for qh.DISTround with qh.MERGEexact
 
     if testall,
       test all facets for qh.MERGEexact post-merging
     else
       test qh.newfacet_list
 
     if qh.MERGEexact,
       allows coplanar ridges
       skips convexity test while qh.ZEROall_ok
 
   returns:
     True if all facets !flipped, !dupridge, normal
          if all horizon facets are simplicial
          if all vertices are clearly below neighbor
          if all opposite vertices of horizon are below
     clears qh.ZEROall_ok if any problems or coplanar facets
 
   notes:
     uses qh.vertex_visit
     horizon facets may define multiple new facets
 
   design:
     for all facets in qh.newfacet_list or qh.facet_list
       check for flagged faults (flipped, etc.)
     for all facets in qh.newfacet_list or qh.facet_list
       for each neighbor of facet
         skip horizon facets for qh.newfacet_list
         test the opposite vertex
       if qh.newfacet_list
         test the other vertices in the facet's horizon facet
 */
 boolT qh_checkzero(qhT *qh, boolT testall) {
   facetT *facet, *neighbor, **neighborp;
   facetT *horizon, *facetlist;
   int neighbor_i;
   vertexT *vertex, **vertexp;
   realT dist;
 
   if (testall)
     facetlist= qh->facet_list;
   else {
     facetlist= qh->newfacet_list;
     FORALLfacet_(facetlist) {
       horizon= SETfirstt_(facet->neighbors, facetT);
       if (!horizon->simplicial)
         goto LABELproblem;
       if (facet->flipped || facet->dupridge || !facet->normal)
         goto LABELproblem;
     }
     if (qh->MERGEexact && qh->ZEROall_ok) {
       trace2((qh, qh->ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));
       return True;
     }
   }
   FORALLfacet_(facetlist) {
     qh->vertex_visit++;
     neighbor_i= 0;
     horizon= NULL;
     FOREACHneighbor_(facet) {
       if (!neighbor_i && !testall) {
         horizon= neighbor;
         neighbor_i++;
         continue; /* horizon facet tested in qh_findhorizon */
       }
       vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
       vertex->visitid= qh->vertex_visit;
       zzinc_(Zdistzero);
       qh_distplane(qh, vertex->point, neighbor, &dist);
       if (dist >= -qh->DISTround) {
         qh->ZEROall_ok= False;
         if (!qh->MERGEexact || testall || dist > qh->DISTround)
           goto LABELnonconvex;
       }
     }
     if (!testall) {
       FOREACHvertex_(horizon->vertices) {
         if (vertex->visitid != qh->vertex_visit) {
           zzinc_(Zdistzero);
           qh_distplane(qh, vertex->point, facet, &dist);
           if (dist >= -qh->DISTround) {
             qh->ZEROall_ok= False;
             if (!qh->MERGEexact || dist > qh->DISTround)
               goto LABELnonconvex;
           }
           break;
         }
       }
     }
   }
   trace2((qh, qh->ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,
         (qh->MERGEexact && !testall) ?
            "not concave, flipped, or duplicate ridged" : "clearly convex"));
   return True;
 
  LABELproblem:
   qh->ZEROall_ok= False;
   trace2((qh, qh->ferr, 2013, "qh_checkzero: facet f%d needs pre-merging\n",
        facet->id));
   return False;
 
  LABELnonconvex:
   trace2((qh, qh->ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
          facet->id, neighbor->id, vertex->id, dist));
   return False;
 } /* checkzero */
 
 /*---------------------------------
 
   qh_compareangle(angle1, angle2 )
     used by qsort() to order merges by angle
 */
 int qh_compareangle(const void *p1, const void *p2) {
   const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
 
   return((a->angle > b->angle) ? 1 : -1);
 } /* compareangle */
 
 /*---------------------------------
 
   qh_comparemerge(merge1, merge2 )
     used by qsort() to order merges
 */
 int qh_comparemerge(const void *p1, const void *p2) {
   const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
 
   return(a->type - b->type);
 } /* comparemerge */
 
 /*---------------------------------
 
   qh_comparevisit(vertex1, vertex2 )
     used by qsort() to order vertices by their visitid
 */
 int qh_comparevisit(const void *p1, const void *p2) {
   const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);
 
   return(a->visitid - b->visitid);
 } /* comparevisit */
 
 /*---------------------------------
 
   qh_copynonconvex(qh, atridge )
     set non-convex flag on other ridges (if any) between same neighbors
 
   notes:
     may be faster if use smaller ridge set
 
   design:
     for each ridge of atridge's top facet
       if ridge shares the same neighbor
         set nonconvex flag
 */
 void qh_copynonconvex(qhT *qh, ridgeT *atridge) {
   facetT *facet, *otherfacet;
   ridgeT *ridge, **ridgep;
 
   facet= atridge->top;
   otherfacet= atridge->bottom;
   FOREACHridge_(facet->ridges) {
     if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {
       ridge->nonconvex= True;
       trace4((qh, qh->ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",
               atridge->id, ridge->id));
       break;
     }
   }
 } /* copynonconvex */
 
 /*---------------------------------
 
   qh_degen_redundant_facet(qh, facet )
     check facet for degen. or redundancy
 
   notes:
     bumps vertex_visit
     called if a facet was redundant but no longer is (qh_merge_degenredundant)
     qh_appendmergeset() only appends first reference to facet (i.e., redundant)
 
   see:
     qh_degen_redundant_neighbors()
 
   design:
     test for redundant neighbor
     test for degenerate facet
 */
 void qh_degen_redundant_facet(qhT *qh, facetT *facet) {
   vertexT *vertex, **vertexp;
   facetT *neighbor, **neighborp;
 
   trace4((qh, qh->ferr, 4021, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
           facet->id));
   FOREACHneighbor_(facet) {
     qh->vertex_visit++;
     FOREACHvertex_(neighbor->vertices)
       vertex->visitid= qh->vertex_visit;
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh->vertex_visit)
         break;
     }
     if (!vertex) {
       qh_appendmergeset(qh, facet, neighbor, MRGredundant, NULL);
       trace2((qh, qh->ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id));
       return;
     }
   }
   if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
     qh_appendmergeset(qh, facet, facet, MRGdegen, NULL);
     trace2((qh, qh->ferr, 2016, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
   }
 } /* degen_redundant_facet */
 
 
 /*---------------------------------
 
   qh_degen_redundant_neighbors(qh, facet, delfacet,  )
     append degenerate and redundant neighbors to facet_mergeset
     if delfacet,
       only checks neighbors of both delfacet and facet
     also checks current facet for degeneracy
 
   notes:
     bumps vertex_visit
     called for each qh_mergefacet() and qh_mergecycle()
     merge and statistics occur in merge_nonconvex
     qh_appendmergeset() only appends first reference to facet (i.e., redundant)
       it appends redundant facets after degenerate ones
 
     a degenerate facet has fewer than hull_dim neighbors
     a redundant facet's vertices is a subset of its neighbor's vertices
     tests for redundant merges first (appendmergeset is nop for others)
     in a merge, only needs to test neighbors of merged facet
 
   see:
     qh_merge_degenredundant() and qh_degen_redundant_facet()
 
   design:
     test for degenerate facet
     test for redundant neighbor
     test for degenerate neighbor
 */
 void qh_degen_redundant_neighbors(qhT *qh, facetT *facet, facetT *delfacet) {
   vertexT *vertex, **vertexp;
   facetT *neighbor, **neighborp;
   int size;
 
   trace4((qh, qh->ferr, 4022, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n",
           facet->id, getid_(delfacet)));
   if ((size= qh_setsize(qh, facet->neighbors)) < qh->hull_dim) {
     qh_appendmergeset(qh, facet, facet, MRGdegen, NULL);
     trace2((qh, qh->ferr, 2017, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
   }
   if (!delfacet)
     delfacet= facet;
   qh->vertex_visit++;
   FOREACHvertex_(facet->vertices)
     vertex->visitid= qh->vertex_visit;
   FOREACHneighbor_(delfacet) {
     /* uses early out instead of checking vertex count */
     if (neighbor == facet)
       continue;
     FOREACHvertex_(neighbor->vertices) {
       if (vertex->visitid != qh->vertex_visit)
         break;
     }
     if (!vertex) {
       qh_appendmergeset(qh, neighbor, facet, MRGredundant, NULL);
       trace2((qh, qh->ferr, 2018, "qh_degen_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id));
     }
   }
   FOREACHneighbor_(delfacet) {   /* redundant merges occur first */
     if (neighbor == facet)
       continue;
     if ((size= qh_setsize(qh, neighbor->neighbors)) < qh->hull_dim) {
       qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, NULL);
       trace2((qh, qh->ferr, 2019, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id));
     }
   }
 } /* degen_redundant_neighbors */
 
 
 /*---------------------------------
 
   qh_find_newvertex(qh, oldvertex, vertices, ridges )
     locate new vertex for renaming old vertex
     vertices is a set of possible new vertices
       vertices sorted by number of deleted ridges
 
   returns:
     newvertex or NULL
       each ridge includes both vertex and oldvertex
     vertices sorted by number of deleted ridges
 
   notes:
     modifies vertex->visitid
     new vertex is in one of the ridges
     renaming will not cause a duplicate ridge
     renaming will minimize the number of deleted ridges
     newvertex may not be adjacent in the dual (though unlikely)
 
   design:
     for each vertex in vertices
       set vertex->visitid to number of references in ridges
     remove unvisited vertices
     set qh.vertex_visit above all possible values
     sort vertices by number of references in ridges
     add each ridge to qh.hash_table
     for each vertex in vertices
       look for a vertex that would not cause a duplicate ridge after a rename
 */
 vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges) {
   vertexT *vertex, **vertexp;
   setT *newridges;
   ridgeT *ridge, **ridgep;
   int size, hashsize;
   int hash;
 
 #ifndef qh_NOtrace
   if (qh->IStracing >= 4) {
     qh_fprintf(qh, qh->ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",
              oldvertex->id);
     FOREACHvertex_(vertices)
       qh_fprintf(qh, qh->ferr, 8064, "v%d ", vertex->id);
     FOREACHridge_(ridges)
       qh_fprintf(qh, qh->ferr, 8065, "r%d ", ridge->id);
     qh_fprintf(qh, qh->ferr, 8066, "\n");
   }
 #endif
   FOREACHvertex_(vertices)
     vertex->visitid= 0;
   FOREACHridge_(ridges) {
     FOREACHvertex_(ridge->vertices)
       vertex->visitid++;
   }
   FOREACHvertex_(vertices) {
     if (!vertex->visitid) {
       qh_setdelnth(qh, vertices, SETindex_(vertices,vertex));
       vertexp--; /* repeat since deleted this vertex */
     }
   }
   qh->vertex_visit += (unsigned int)qh_setsize(qh, ridges);
   if (!qh_setsize(qh, vertices)) {
     trace4((qh, qh->ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",
             oldvertex->id));
     return NULL;
   }
   qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(qh, vertices),
                 sizeof(vertexT *), qh_comparevisit);
   /* can now use qh->vertex_visit */
   if (qh->PRINTstatistics) {
     size= qh_setsize(qh, vertices);
     zinc_(Zintersect);
     zadd_(Zintersecttot, size);
     zmax_(Zintersectmax, size);
   }
   hashsize= qh_newhashtable(qh, qh_setsize(qh, ridges));
   FOREACHridge_(ridges)
     qh_hashridge(qh, qh->hash_table, hashsize, ridge, oldvertex);
   FOREACHvertex_(vertices) {
     newridges= qh_vertexridges(qh, vertex);
     FOREACHridge_(newridges) {
       if (qh_hashridge_find(qh, qh->hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
         zinc_(Zdupridge);
         break;
       }
     }
     qh_settempfree(qh, &newridges);
     if (!ridge)
       break;  /* found a rename */
   }
   if (vertex) {
     /* counted in qh_renamevertex */
     trace2((qh, qh->ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
       vertex->id, oldvertex->id, qh_setsize(qh, vertices), qh_setsize(qh, ridges)));
   }else {
     zinc_(Zfindfail);
     trace0((qh, qh->ferr, 14, "qh_find_newvertex: no vertex for renaming v%d(all duplicated ridges) during p%d\n",
       oldvertex->id, qh->furthest_id));
   }
   qh_setfree(qh, &qh->hash_table);
   return vertex;
 } /* find_newvertex */
 
 /*---------------------------------
 
   qh_findbest_test(qh, testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )
     test neighbor of facet for qh_findbestneighbor()
     if testcentrum,
       tests centrum (assumes it is defined)
     else
       tests vertices
 
   returns:
     if a better facet (i.e., vertices/centrum of facet closer to neighbor)
       updates bestfacet, dist, mindist, and maxdist
 */
 void qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
       facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
   realT dist, mindist, maxdist;
 
   if (testcentrum) {
     zzinc_(Zbestdist);
     qh_distplane(qh, facet->center, neighbor, &dist);
     dist *= qh->hull_dim; /* estimate furthest vertex */
     if (dist < 0) {
       maxdist= 0;
       mindist= dist;
       dist= -dist;
     }else {
       mindist= 0;
       maxdist= dist;
     }
   }else
     dist= qh_getdistance(qh, facet, neighbor, &mindist, &maxdist);
   if (dist < *distp) {
     *bestfacet= neighbor;
     *mindistp= mindist;
     *maxdistp= maxdist;
     *distp= dist;
   }
 } /* findbest_test */
 
 /*---------------------------------
 
   qh_findbestneighbor(qh, facet, dist, mindist, maxdist )
     finds best neighbor (least dist) of a facet for merging
 
   returns:
     returns min and max distances and their max absolute value
 
   notes:
     avoids merging old into new
     assumes ridge->nonconvex only set on one ridge between a pair of facets
     could use an early out predicate but not worth it
 
   design:
     if a large facet
       will test centrum
     else
       will test vertices
     if a large facet
       test nonconvex neighbors for best merge
     else
       test all neighbors for the best merge
     if testing centrum
       get distance information
 */
 facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
   facetT *neighbor, **neighborp, *bestfacet= NULL;
   ridgeT *ridge, **ridgep;
   boolT nonconvex= True, testcentrum= False;
   int size= qh_setsize(qh, facet->vertices);
 
   *distp= REALmax;
   if (size > qh_BESTcentrum2 * qh->hull_dim + qh_BESTcentrum) {
     testcentrum= True;
     zinc_(Zbestcentrum);
     if (!facet->center)
        facet->center= qh_getcentrum(qh, facet);
   }
   if (size > qh->hull_dim + qh_BESTnonconvex) {
     FOREACHridge_(facet->ridges) {
       if (ridge->nonconvex) {
         neighbor= otherfacet_(ridge, facet);
         qh_findbest_test(qh, testcentrum, facet, neighbor,
                           &bestfacet, distp, mindistp, maxdistp);
       }
     }
   }
   if (!bestfacet) {
     nonconvex= False;
     FOREACHneighbor_(facet)
       qh_findbest_test(qh, testcentrum, facet, neighbor,
                         &bestfacet, distp, mindistp, maxdistp);
   }
   if (!bestfacet) {
     qh_fprintf(qh, qh->ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
 
     qh_errexit(qh, qh_ERRqhull, facet, NULL);
   }
   if (testcentrum)
     qh_getdistance(qh, facet, bestfacet, mindistp, maxdistp);
   trace3((qh, qh->ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
      bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
   return(bestfacet);
 } /* findbestneighbor */
 
 
 /*---------------------------------
 
   qh_flippedmerges(qh, facetlist, wasmerge )
     merge flipped facets into best neighbor
     assumes qh.facet_mergeset at top of temporary stack
 
   returns:
     no flipped facets on facetlist
     sets wasmerge if merge occurred
     degen/redundant merges passed through
 
   notes:
     othermerges not needed since qh.facet_mergeset is empty before & after
       keep it in case of change
 
   design:
     append flipped facets to qh.facetmergeset
     for each flipped merge
       find best neighbor
       merge facet into neighbor
       merge degenerate and redundant facets
     remove flipped merges from qh.facet_mergeset
 */
 void qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge) {
   facetT *facet, *neighbor, *facet1;
   realT dist, mindist, maxdist;
   mergeT *merge, **mergep;
   setT *othermerges;
   int nummerge=0;
 
   trace4((qh, qh->ferr, 4024, "qh_flippedmerges: begin\n"));
   FORALLfacet_(facetlist) {
     if (facet->flipped && !facet->visible)
       qh_appendmergeset(qh, facet, facet, MRGflip, NULL);
   }
   othermerges= qh_settemppop(qh); /* was facet_mergeset */
   qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
   qh_settemppush(qh, othermerges);
   FOREACHmerge_(othermerges) {
     facet1= merge->facet1;
     if (merge->type != MRGflip || facet1->visible)
       continue;
     if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
       qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
     neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
     trace0((qh, qh->ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
       facet1->id, neighbor->id, dist, qh->furthest_id));
     qh_mergefacet(qh, facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);
     nummerge++;
     if (qh->PRINTstatistics) {
       zinc_(Zflipped);
       wadd_(Wflippedtot, dist);
       wmax_(Wflippedmax, dist);
     }
     qh_merge_degenredundant(qh);
   }
   FOREACHmerge_(othermerges) {
     if (merge->facet1->visible || merge->facet2->visible)
       qh_memfree(qh, merge, (int)sizeof(mergeT));
     else
       qh_setappend(qh, &qh->facet_mergeset, merge);
   }
   qh_settempfree(qh, &othermerges);
   if (nummerge)
     *wasmerge= True;
   trace1((qh, qh->ferr, 1010, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
 } /* flippedmerges */
 
 
 /*---------------------------------
 
   qh_forcedmerges(qh, wasmerge )
     merge duplicated ridges
 
   returns:
     removes all duplicate ridges on facet_mergeset
     wasmerge set if merge
     qh.facet_mergeset may include non-forced merges(none for now)
     qh.degen_mergeset includes degen/redun merges
 
   notes:
     duplicate ridges occur when the horizon is pinched,
         i.e. a subridge occurs in more than two horizon ridges.
      could rename vertices that pinch the horizon
     assumes qh_merge_degenredundant() has not be called
     othermerges isn't needed since facet_mergeset is empty afterwards
       keep it in case of change
 
   design:
     for each duplicate ridge
       find current facets by chasing f.replace links
       determine best direction for facet
       merge one facet into the other
       remove duplicate ridges from qh.facet_mergeset
 */
 void qh_forcedmerges(qhT *qh, boolT *wasmerge) {
   facetT *facet1, *facet2;
   mergeT *merge, **mergep;
   realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;
   setT *othermerges;
   int nummerge=0, numflip=0;
 
   if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
     qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
   trace4((qh, qh->ferr, 4025, "qh_forcedmerges: begin\n"));
   othermerges= qh_settemppop(qh); /* was facet_mergeset */
   qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
   qh_settemppush(qh, othermerges);
   FOREACHmerge_(othermerges) {
     if (merge->type != MRGridge)
         continue;
     facet1= merge->facet1;
     facet2= merge->facet2;
     while (facet1->visible)      /* must exist, no qh_merge_degenredunant */
       facet1= facet1->f.replace; /* previously merged facet */
     while (facet2->visible)
       facet2= facet2->f.replace; /* previously merged facet */
     if (facet1 == facet2)
       continue;
     if (!qh_setin(facet2->neighbors, facet1)) {
       qh_fprintf(qh, qh->ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",
                merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
       qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
     }
     if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
       qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
     dist1= qh_getdistance(qh, facet1, facet2, &mindist1, &maxdist1);
     dist2= qh_getdistance(qh, facet2, facet1, &mindist2, &maxdist2);
     trace0((qh, qh->ferr, 16, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g during p%d\n",
             facet1->id, facet2->id, dist1, dist2, qh->furthest_id));
     if (dist1 < dist2)
       qh_mergefacet(qh, facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);
     else {
       qh_mergefacet(qh, facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);
       dist1= dist2;
       facet1= facet2;
     }
     if (facet1->flipped) {
       zinc_(Zmergeflipdup);
       numflip++;
     }else
       nummerge++;
     if (qh->PRINTstatistics) {
       zinc_(Zduplicate);
       wadd_(Wduplicatetot, dist1);
       wmax_(Wduplicatemax, dist1);
     }
   }
   FOREACHmerge_(othermerges) {
     if (merge->type == MRGridge)
       qh_memfree(qh, merge, (int)sizeof(mergeT));
     else
       qh_setappend(qh, &qh->facet_mergeset, merge);
   }
   qh_settempfree(qh, &othermerges);
   if (nummerge)
     *wasmerge= True;
   trace1((qh, qh->ferr, 1011, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n",
                 nummerge, numflip));
 } /* forcedmerges */
 
 
 /*---------------------------------
 
   qh_getmergeset(qh, facetlist )
     determines nonconvex facets on facetlist
     tests !tested ridges and nonconvex ridges of !tested facets
 
   returns:
     returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
     all ridges tested
 
   notes:
     assumes no nonconvex ridges with both facets tested
     uses facet->tested/ridge->tested to prevent duplicate tests
     can not limit tests to modified ridges since the centrum changed
     uses qh.visit_id
 
   see:
     qh_getmergeset_initial()
 
   design:
     for each facet on facetlist
       for each ridge of facet
         if untested ridge
           test ridge for convexity
           if non-convex
             append ridge to qh.facet_mergeset
     sort qh.facet_mergeset by angle
 */
 void qh_getmergeset(qhT *qh, facetT *facetlist) {
   facetT *facet, *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int nummerges;
 
   nummerges= qh_setsize(qh, qh->facet_mergeset);
   trace4((qh, qh->ferr, 4026, "qh_getmergeset: started.\n"));
   qh->visit_id++;
   FORALLfacet_(facetlist) {
     if (facet->tested)
       continue;
     facet->visitid= qh->visit_id;
     facet->tested= True;  /* must be non-simplicial due to merge */
     FOREACHneighbor_(facet)
       neighbor->seen= False;
     FOREACHridge_(facet->ridges) {
       if (ridge->tested && !ridge->nonconvex)
         continue;
       /* if tested & nonconvex, need to append merge */
       neighbor= otherfacet_(ridge, facet);
       if (neighbor->seen) {
         ridge->tested= True;
         ridge->nonconvex= False;
       }else if (neighbor->visitid != qh->visit_id) {
         ridge->tested= True;
         ridge->nonconvex= False;
         neighbor->seen= True;      /* only one ridge is marked nonconvex */
         if (qh_test_appendmerge(qh, facet, neighbor))
           ridge->nonconvex= True;
       }
     }
   }
   nummerges= qh_setsize(qh, qh->facet_mergeset);
   if (qh->ANGLEmerge)
     qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);
   else
     qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);
   if (qh->POSTmerging) {
     zadd_(Zmergesettot2, nummerges);
   }else {
     zadd_(Zmergesettot, nummerges);
     zmax_(Zmergesetmax, nummerges);
   }
   trace2((qh, qh->ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));
 } /* getmergeset */
 
 
 /*---------------------------------
 
   qh_getmergeset_initial(qh, facetlist )
     determine initial qh.facet_mergeset for facets
     tests all facet/neighbor pairs on facetlist
 
   returns:
     sorted qh.facet_mergeset with nonconvex ridges
     sets facet->tested, ridge->tested, and ridge->nonconvex
 
   notes:
     uses visit_id, assumes ridge->nonconvex is False
 
   see:
     qh_getmergeset()
 
   design:
     for each facet on facetlist
       for each untested neighbor of facet
         test facet and neighbor for convexity
         if non-convex
           append merge to qh.facet_mergeset
           mark one of the ridges as nonconvex
     sort qh.facet_mergeset by angle
 */
 void qh_getmergeset_initial(qhT *qh, facetT *facetlist) {
   facetT *facet, *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int nummerges;
 
   qh->visit_id++;
   FORALLfacet_(facetlist) {
     facet->visitid= qh->visit_id;
     facet->tested= True;
     FOREACHneighbor_(facet) {
       if (neighbor->visitid != qh->visit_id) {
         if (qh_test_appendmerge(qh, facet, neighbor)) {
           FOREACHridge_(neighbor->ridges) {
             if (facet == otherfacet_(ridge, neighbor)) {
               ridge->nonconvex= True;
               break;    /* only one ridge is marked nonconvex */
             }
           }
         }
       }
     }
     FOREACHridge_(facet->ridges)
       ridge->tested= True;
   }
   nummerges= qh_setsize(qh, qh->facet_mergeset);
   if (qh->ANGLEmerge)
     qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);
   else
     qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);
   if (qh->POSTmerging) {
     zadd_(Zmergeinittot2, nummerges);
   }else {
     zadd_(Zmergeinittot, nummerges);
     zmax_(Zmergeinitmax, nummerges);
   }
   trace2((qh, qh->ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));
 } /* getmergeset_initial */
 
 
 /*---------------------------------
 
   qh_hashridge(qh, hashtable, hashsize, ridge, oldvertex )
     add ridge to hashtable without oldvertex
 
   notes:
     assumes hashtable is large enough
 
   design:
     determine hash value for ridge without oldvertex
     find next empty slot for ridge
 */
 void qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
   int hash;
   ridgeT *ridgeA;
 
   hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, oldvertex);
   while (True) {
     if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
       SETelem_(hashtable, hash)= ridge;
       break;
     }else if (ridgeA == ridge)
       break;
     if (++hash == hashsize)
       hash= 0;
   }
 } /* hashridge */
 
 
 /*---------------------------------
 
   qh_hashridge_find(qh, hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
     returns matching ridge without oldvertex in hashtable
       for ridge without vertex
     if oldvertex is NULL
       matches with any one skip
 
   returns:
     matching ridge or NULL
     if no match,
       if ridge already in   table
         hashslot= -1
       else
         hashslot= next NULL index
 
   notes:
     assumes hashtable is large enough
     can't match ridge to itself
 
   design:
     get hash value for ridge without vertex
     for each hashslot
       return match if ridge matches ridgeA without oldvertex
 */
 ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
               vertexT *vertex, vertexT *oldvertex, int *hashslot) {
   int hash;
   ridgeT *ridgeA;
 
   *hashslot= 0;
   zinc_(Zhashridge);
   hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, vertex);
   while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
     if (ridgeA == ridge)
       *hashslot= -1;
     else {
       zinc_(Zhashridgetest);
       if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))
         return ridgeA;
     }
     if (++hash == hashsize)
       hash= 0;
   }
   if (!*hashslot)
     *hashslot= hash;
   return NULL;
 } /* hashridge_find */
 
 
 /*---------------------------------
 
   qh_makeridges(qh, facet )
     creates explicit ridges between simplicial facets
 
   returns:
     facet with ridges and without qh_MERGEridge
     ->simplicial is False
 
   notes:
     allows qh_MERGEridge flag
     uses existing ridges
     duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
 
   see:
     qh_mergecycle_ridges()
 
   design:
     look for qh_MERGEridge neighbors
     mark neighbors that already have ridges
     for each unprocessed neighbor of facet
       create a ridge for neighbor and facet
     if any qh_MERGEridge neighbors
       delete qh_MERGEridge flags (already handled by qh_mark_dupridges)
 */
 void qh_makeridges(qhT *qh, facetT *facet) {
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   int neighbor_i, neighbor_n;
   boolT toporient, mergeridge= False;
 
   if (!facet->simplicial)
     return;
   trace4((qh, qh->ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));
   facet->simplicial= False;
   FOREACHneighbor_(facet) {
     if (neighbor == qh_MERGEridge)
       mergeridge= True;
     else
       neighbor->seen= False;
   }
   FOREACHridge_(facet->ridges)
     otherfacet_(ridge, facet)->seen= True;
   FOREACHneighbor_i_(qh, facet) {
     if (neighbor == qh_MERGEridge)
       continue;  /* fixed by qh_mark_dupridges */
     else if (!neighbor->seen) {  /* no current ridges */
       ridge= qh_newridge(qh);
       ridge->vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
                                                           neighbor_i, 0);
       toporient= facet->toporient ^ (neighbor_i & 0x1);
       if (toporient) {
         ridge->top= facet;
         ridge->bottom= neighbor;
       }else {
         ridge->top= neighbor;
         ridge->bottom= facet;
       }
 #if 0 /* this also works */
       flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
       if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
         ridge->top= neighbor;
         ridge->bottom= facet;
       }else {
         ridge->top= facet;
         ridge->bottom= neighbor;
       }
 #endif
       qh_setappend(qh, &(facet->ridges), ridge);
       qh_setappend(qh, &(neighbor->ridges), ridge);
     }
   }
   if (mergeridge) {
     while (qh_setdel(facet->neighbors, qh_MERGEridge))
       ; /* delete each one */
   }
 } /* makeridges */
 
 
 /*---------------------------------
 
   qh_mark_dupridges(qh, facetlist )
     add duplicated ridges to qh.facet_mergeset
     facet->dupridge is true
 
   returns:
     duplicate ridges on qh.facet_mergeset
     ->mergeridge/->mergeridge2 set
     duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge
     no MERGEridges in neighbor sets
 
   notes:
     duplicate ridges occur when the horizon is pinched,
         i.e. a subridge occurs in more than two horizon ridges.
     could rename vertices that pinch the horizon
     uses qh.visit_id
 
   design:
     for all facets on facetlist
       if facet contains a duplicate ridge
         for each neighbor of facet
           if neighbor marked qh_MERGEridge (one side of the merge)
             set facet->mergeridge
           else
             if neighbor contains a duplicate ridge
             and the back link is qh_MERGEridge
               append duplicate ridge to qh.facet_mergeset
    for each duplicate ridge
      make ridge sets in preparation for merging
      remove qh_MERGEridge from neighbor set
    for each duplicate ridge
      restore the missing neighbor from the neighbor set that was qh_MERGEridge
      add the missing ridge for this neighbor
 */
 void qh_mark_dupridges(qhT *qh, facetT *facetlist) {
   facetT *facet, *neighbor, **neighborp;
   int nummerge=0;
   mergeT *merge, **mergep;
 
 
   trace4((qh, qh->ferr, 4028, "qh_mark_dupridges: identify duplicate ridges\n"));
   FORALLfacet_(facetlist) {
     if (facet->dupridge) {
       FOREACHneighbor_(facet) {
         if (neighbor == qh_MERGEridge) {
           facet->mergeridge= True;
           continue;
         }
         if (neighbor->dupridge
         && !qh_setin(neighbor->neighbors, facet)) { /* qh_MERGEridge */
           qh_appendmergeset(qh, facet, neighbor, MRGridge, NULL);
           facet->mergeridge2= True;
           facet->mergeridge= True;
           nummerge++;
         }
       }
     }
   }
   if (!nummerge)
     return;
   FORALLfacet_(facetlist) {            /* gets rid of qh_MERGEridge */
     if (facet->mergeridge && !facet->mergeridge2)
       qh_makeridges(qh, facet);
   }
   FOREACHmerge_(qh->facet_mergeset) {   /* restore the missing neighbors */
     if (merge->type == MRGridge) {
       qh_setappend(qh, &merge->facet2->neighbors, merge->facet1);
       qh_makeridges(qh, merge->facet1);   /* and the missing ridges */
     }
   }
   trace1((qh, qh->ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges\n",
                 nummerge));
 } /* mark_dupridges */
 
 /*---------------------------------
 
   qh_maydropneighbor(qh, facet )
     drop neighbor relationship if no ridge between facet and neighbor
 
   returns:
     neighbor sets updated
     appends degenerate facets to qh.facet_mergeset
 
   notes:
     won't cause redundant facets since vertex inclusion is the same
     may drop vertex and neighbor if no ridge
     uses qh.visit_id
 
   design:
     visit all neighbors with ridges
     for each unvisited neighbor of facet
       delete neighbor and facet from the neighbor sets
       if neighbor becomes degenerate
         append neighbor to qh.degen_mergeset
     if facet is degenerate
       append facet to qh.degen_mergeset
 */
 void qh_maydropneighbor(qhT *qh, facetT *facet) {
   ridgeT *ridge, **ridgep;
   realT angledegen= qh_ANGLEdegen;
   facetT *neighbor, **neighborp;
 
   qh->visit_id++;
   trace4((qh, qh->ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
           facet->id));
   FOREACHridge_(facet->ridges) {
     ridge->top->visitid= qh->visit_id;
     ridge->bottom->visitid= qh->visit_id;
   }
   FOREACHneighbor_(facet) {
     if (neighbor->visitid != qh->visit_id) {
       trace0((qh, qh->ferr, 17, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",
             facet->id, neighbor->id, qh->furthest_id));
       zinc_(Zdropneighbor);
       qh_setdel(facet->neighbors, neighbor);
       neighborp--;  /* repeat, deleted a neighbor */
       qh_setdel(neighbor->neighbors, facet);
       if (qh_setsize(qh, neighbor->neighbors) < qh->hull_dim) {
         zinc_(Zdropdegen);
         qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, &angledegen);
         trace2((qh, qh->ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
       }
     }
   }
   if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
     zinc_(Zdropdegen);
     qh_appendmergeset(qh, facet, facet, MRGdegen, &angledegen);
     trace2((qh, qh->ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
   }
 } /* maydropneighbor */
 
 
 /*---------------------------------
 
   qh_merge_degenredundant(qh)
     merge all degenerate and redundant facets
     qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()
 
   returns:
     number of merges performed
     resets facet->degenerate/redundant
     if deleted (visible) facet has no neighbors
       sets ->f.replace to NULL
 
   notes:
     redundant merges happen before degenerate ones
     merging and renaming vertices can result in degen/redundant facets
 
   design:
     for each merge on qh.degen_mergeset
       if redundant merge
         if non-redundant facet merged into redundant facet
           recheck facet for redundancy
         else
           merge redundant facet into other facet
 */
 int qh_merge_degenredundant(qhT *qh) {
   int size;
   mergeT *merge;
   facetT *bestneighbor, *facet1, *facet2;
   realT dist, mindist, maxdist;
   vertexT *vertex, **vertexp;
   int nummerges= 0;
   mergeType mergetype;
 
   while ((merge= (mergeT*)qh_setdellast(qh->degen_mergeset))) {
     facet1= merge->facet1;
     facet2= merge->facet2;
     mergetype= merge->type;
     qh_memfree(qh, merge, (int)sizeof(mergeT));
     if (facet1->visible)
       continue;
     facet1->degenerate= False;
     facet1->redundant= False;
     if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
       qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
     if (mergetype == MRGredundant) {
       zinc_(Zneighbor);
       while (facet2->visible) {
         if (!facet2->f.replace) {
           qh_fprintf(qh, qh->ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",
                facet1->id, facet2->id);
           qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
         }
         facet2= facet2->f.replace;
       }
       if (facet1 == facet2) {
         qh_degen_redundant_facet(qh, facet1); /* in case of others */
         continue;
       }
       trace2((qh, qh->ferr, 2025, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",
             facet1->id, facet2->id));
       qh_mergefacet(qh, facet1, facet2, NULL, NULL, !qh_MERGEapex);
       /* merge distance is already accounted for */
       nummerges++;
     }else {  /* mergetype == MRGdegen, other merges may have fixed */
       if (!(size= qh_setsize(qh, facet1->neighbors))) {
         zinc_(Zdelfacetdup);
         trace2((qh, qh->ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
         qh_willdelete(qh, facet1, NULL);
         FOREACHvertex_(facet1->vertices) {
           qh_setdel(vertex->neighbors, facet1);
           if (!SETfirst_(vertex->neighbors)) {
             zinc_(Zdegenvertex);
             trace2((qh, qh->ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
                  vertex->id, facet1->id));
             vertex->deleted= True;
             qh_setappend(qh, &qh->del_vertices, vertex);
           }
         }
         nummerges++;
       }else if (size < qh->hull_dim) {
         bestneighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
         trace2((qh, qh->ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
               facet1->id, size, bestneighbor->id, dist));
         qh_mergefacet(qh, facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
         nummerges++;
         if (qh->PRINTstatistics) {
           zinc_(Zdegen);
           wadd_(Wdegentot, dist);
           wmax_(Wdegenmax, dist);
         }
       } /* else, another merge fixed the degeneracy and redundancy tested */
     }
   }
   return nummerges;
 } /* merge_degenredundant */
 
 /*---------------------------------
 
   qh_merge_nonconvex(qh, facet1, facet2, mergetype )
     remove non-convex ridge between facet1 into facet2
     mergetype gives why the facet's are non-convex
 
   returns:
     merges one of the facets into the best neighbor
 
   design:
     if one of the facets is a new facet
       prefer merging new facet into old facet
     find best neighbors for both facets
     merge the nearest facet into its best neighbor
     update the statistics
 */
 void qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
   facetT *bestfacet, *bestneighbor, *neighbor;
   realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
 
   if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
     qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
   trace3((qh, qh->ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
       zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
   /* concave or coplanar */
   if (!facet1->newfacet) {
     bestfacet= facet2;   /* avoid merging old facet if new is ok */
     facet2= facet1;
     facet1= bestfacet;
   }else
     bestfacet= facet1;
   bestneighbor= qh_findbestneighbor(qh, bestfacet, &dist, &mindist, &maxdist);
   neighbor= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
   if (dist < dist2) {
     qh_mergefacet(qh, bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
   }else if (qh->AVOIDold && !facet2->newfacet
   && ((mindist >= -qh->MAXcoplanar && maxdist <= qh->max_outside)
        || dist * 1.5 < dist2)) {
     zinc_(Zavoidold);
     wadd_(Wavoidoldtot, dist);
     wmax_(Wavoidoldmax, dist);
     trace2((qh, qh->ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
            facet2->id, dist2, facet1->id, dist2));
     qh_mergefacet(qh, bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
   }else {
     qh_mergefacet(qh, facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);
     dist= dist2;
   }
   if (qh->PRINTstatistics) {
     if (mergetype == MRGanglecoplanar) {
       zinc_(Zacoplanar);
       wadd_(Wacoplanartot, dist);
       wmax_(Wacoplanarmax, dist);
     }else if (mergetype == MRGconcave) {
       zinc_(Zconcave);
       wadd_(Wconcavetot, dist);
       wmax_(Wconcavemax, dist);
     }else { /* MRGcoplanar */
       zinc_(Zcoplanar);
       wadd_(Wcoplanartot, dist);
       wmax_(Wcoplanarmax, dist);
     }
   }
 } /* merge_nonconvex */
 
 /*---------------------------------
 
   qh_mergecycle(qh, samecycle, newfacet )
     merge a cycle of facets starting at samecycle into a newfacet
     newfacet is a horizon facet with ->normal
     samecycle facets are simplicial from an apex
 
   returns:
     initializes vertex neighbors on first merge
     samecycle deleted (placed on qh.visible_list)
     newfacet at end of qh.facet_list
     deleted vertices on qh.del_vertices
 
   see:
     qh_mergefacet()
     called by qh_mergecycle_all() for multiple, same cycle facets
 
   design:
     make vertex neighbors if necessary
     make ridges for newfacet
     merge neighbor sets of samecycle into newfacet
     merge ridges of samecycle into newfacet
     merge vertex neighbors of samecycle into newfacet
     make apex of samecycle the apex of newfacet
     if newfacet wasn't a new facet
       add its vertices to qh.newvertex_list
     delete samecycle facets a make newfacet a newfacet
 */
 void qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet) {
   int traceonce= False, tracerestore= 0;
   vertexT *apex;
 #ifndef qh_NOtrace
   facetT *same;
 #endif
 
   if (newfacet->tricoplanar) {
     if (!qh->TRInormals) {
       qh_fprintf(qh, qh->ferr, 6224, "Qhull internal error (qh_mergecycle): does not work for tricoplanar facets.  Use option 'Q11'\n");
       qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
     }
     newfacet->tricoplanar= False;
     newfacet->keepcentrum= False;
   }
   if (!qh->VERTEXneighbors)
     qh_vertexneighbors(qh);
   zzinc_(Ztotmerge);
   if (qh->REPORTfreq2 && qh->POSTmerging) {
     if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
       qh_tracemerging(qh);
   }
 #ifndef qh_NOtrace
   if (qh->TRACEmerge == zzval_(Ztotmerge))
     qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
   trace2((qh, qh->ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",
         zzval_(Ztotmerge), samecycle->id, newfacet->id));
   if (newfacet == qh->tracefacet) {
     tracerestore= qh->IStracing;
     qh->IStracing= 4;
     qh_fprintf(qh, qh->ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
                zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh->furthest_id);
     traceonce= True;
   }
   if (qh->IStracing >=4) {
     qh_fprintf(qh, qh->ferr, 8069, "  same cycle:");
     FORALLsame_cycle_(samecycle)
       qh_fprintf(qh, qh->ferr, 8070, " f%d", same->id);
     qh_fprintf(qh, qh->ferr, 8071, "\n");
   }
   if (qh->IStracing >=4)
     qh_errprint(qh, "MERGING CYCLE", samecycle, newfacet, NULL, NULL);
 #endif /* !qh_NOtrace */
   apex= SETfirstt_(samecycle->vertices, vertexT);
   qh_makeridges(qh, newfacet);
   qh_mergecycle_neighbors(qh, samecycle, newfacet);
   qh_mergecycle_ridges(qh, samecycle, newfacet);
   qh_mergecycle_vneighbors(qh, samecycle, newfacet);
   if (SETfirstt_(newfacet->vertices, vertexT) != apex)
     qh_setaddnth(qh, &newfacet->vertices, 0, apex);  /* apex has last id */
   if (!newfacet->newfacet)
     qh_newvertices(qh, newfacet->vertices);
   qh_mergecycle_facets(qh, samecycle, newfacet);
   qh_tracemerge(qh, samecycle, newfacet);
   /* check for degen_redundant_neighbors after qh_forcedmerges() */
   if (traceonce) {
     qh_fprintf(qh, qh->ferr, 8072, "qh_mergecycle: end of trace facet\n");
     qh->IStracing= tracerestore;
   }
 } /* mergecycle */
 
 /*---------------------------------
 
   qh_mergecycle_all(qh, facetlist, wasmerge )
     merge all samecycles of coplanar facets into horizon
     don't merge facets with ->mergeridge (these already have ->normal)
     all facets are simplicial from apex
     all facet->cycledone == False
 
   returns:
     all newfacets merged into coplanar horizon facets
     deleted vertices on  qh.del_vertices
     sets wasmerge if any merge
 
   see:
     calls qh_mergecycle for multiple, same cycle facets
 
   design:
     for each facet on facetlist
       skip facets with duplicate ridges and normals
       check that facet is in a samecycle (->mergehorizon)
       if facet only member of samecycle
         sets vertex->delridge for all vertices except apex
         merge facet into horizon
       else
         mark all facets in samecycle
         remove facets with duplicate ridges from samecycle
         merge samecycle into horizon (deletes facets from facetlist)
 */
 void qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge) {
   facetT *facet, *same, *prev, *horizon;
   facetT *samecycle= NULL, *nextfacet, *nextsame;
   vertexT *apex, *vertex, **vertexp;
   int cycles=0, total=0, facets, nummerge;
 
   trace2((qh, qh->ferr, 2031, "qh_mergecycle_all: begin\n"));
   for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
     if (facet->normal)
       continue;
     if (!facet->mergehorizon) {
       qh_fprintf(qh, qh->ferr, 6225, "Qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);
       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     }
     horizon= SETfirstt_(facet->neighbors, facetT);
     if (facet->f.samecycle == facet) {
       zinc_(Zonehorizon);
       /* merge distance done in qh_findhorizon */
       apex= SETfirstt_(facet->vertices, vertexT);
       FOREACHvertex_(facet->vertices) {
         if (vertex != apex)
           vertex->delridge= True;
       }
       horizon->f.newcycle= NULL;
       qh_mergefacet(qh, facet, horizon, NULL, NULL, qh_MERGEapex);
     }else {
       samecycle= facet;
       facets= 0;
       prev= facet;
       for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
            same= (same == facet ? NULL :nextsame)) { /* ends at facet */
         nextsame= same->f.samecycle;
         if (same->cycledone || same->visible)
           qh_infiniteloop(qh, same);
         same->cycledone= True;
         if (same->normal) {
           prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
           same->f.samecycle= NULL;
         }else {
           prev= same;
           facets++;
         }
       }
       while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
         nextfacet= nextfacet->next;
       horizon->f.newcycle= NULL;
       qh_mergecycle(qh, samecycle, horizon);
       nummerge= horizon->nummerge + facets;
       if (nummerge > qh_MAXnummerge)
         horizon->nummerge= qh_MAXnummerge;
       else
         horizon->nummerge= (short unsigned int)nummerge;
       zzinc_(Zcyclehorizon);
       total += facets;
       zzadd_(Zcyclefacettot, facets);
       zmax_(Zcyclefacetmax, facets);
     }
     cycles++;
   }
   if (cycles)
     *wasmerge= True;
   trace1((qh, qh->ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));
 } /* mergecycle_all */
 
 /*---------------------------------
 
   qh_mergecycle_facets(qh, samecycle, newfacet )
     finish merge of samecycle into newfacet
 
   returns:
     samecycle prepended to visible_list for later deletion and partitioning
       each facet->f.replace == newfacet
 
     newfacet moved to end of qh.facet_list
       makes newfacet a newfacet (get's facet1->id if it was old)
       sets newfacet->newmerge
       clears newfacet->center (unless merging into a large facet)
       clears newfacet->tested and ridge->tested for facet1
 
     adds neighboring facets to facet_mergeset if redundant or degenerate
 
   design:
     make newfacet a new facet and set its flags
     move samecycle facets to qh.visible_list for later deletion
     unless newfacet is large
       remove its centrum
 */
 void qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet) {
   facetT *same, *next;
 
   trace4((qh, qh->ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));
   qh_removefacet(qh, newfacet);  /* append as a newfacet to end of qh->facet_list */
   qh_appendfacet(qh, newfacet);
   newfacet->newfacet= True;
   newfacet->simplicial= False;
   newfacet->newmerge= True;
 
   for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
     next= same->f.samecycle;  /* reused by willdelete */
     qh_willdelete(qh, same, newfacet);
   }
   if (newfacet->center
       && qh_setsize(qh, newfacet->vertices) <= qh->hull_dim + qh_MAXnewcentrum) {
     qh_memfree(qh, newfacet->center, qh->normal_size);
     newfacet->center= NULL;
   }
   trace3((qh, qh->ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
              samecycle->id, newfacet->id));
 } /* mergecycle_facets */
 
 /*---------------------------------
 
   qh_mergecycle_neighbors(qh, samecycle, newfacet )
     add neighbors for samecycle facets to newfacet
 
   returns:
     newfacet with updated neighbors and vice-versa
     newfacet has ridges
     all neighbors of newfacet marked with qh.visit_id
     samecycle facets marked with qh.visit_id-1
     ridges updated for simplicial neighbors of samecycle with a ridge
 
   notes:
     assumes newfacet not in samecycle
     usually, samecycle facets are new, simplicial facets without internal ridges
       not so if horizon facet is coplanar to two different samecycles
 
   see:
     qh_mergeneighbors()
 
   design:
     check samecycle
     delete neighbors from newfacet that are also in samecycle
     for each neighbor of a facet in samecycle
       if neighbor is simplicial
         if first visit
           move the neighbor relation to newfacet
           update facet links for its ridges
         else
           make ridges for neighbor
           remove samecycle reference
       else
         update neighbor sets
 */
 void qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
   facetT *same, *neighbor, **neighborp;
   int delneighbors= 0, newneighbors= 0;
   unsigned int samevisitid;
   ridgeT *ridge, **ridgep;
 
   samevisitid= ++qh->visit_id;
   FORALLsame_cycle_(samecycle) {
     if (same->visitid == samevisitid || same->visible)
       qh_infiniteloop(qh, samecycle);
     same->visitid= samevisitid;
   }
   newfacet->visitid= ++qh->visit_id;
   trace4((qh, qh->ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));
   FOREACHneighbor_(newfacet) {
     if (neighbor->visitid == samevisitid) {
       SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
       delneighbors++;
     }else
       neighbor->visitid= qh->visit_id;
   }
   qh_setcompact(qh, newfacet->neighbors);
 
   trace4((qh, qh->ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));
   FORALLsame_cycle_(samecycle) {
     FOREACHneighbor_(same) {
       if (neighbor->visitid == samevisitid)
         continue;
       if (neighbor->simplicial) {
         if (neighbor->visitid != qh->visit_id) {
           qh_setappend(qh, &newfacet->neighbors, neighbor);
           qh_setreplace(qh, neighbor->neighbors, same, newfacet);
           newneighbors++;
           neighbor->visitid= qh->visit_id;
           FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
             if (ridge->top == same) {
               ridge->top= newfacet;
               break;
             }else if (ridge->bottom == same) {
               ridge->bottom= newfacet;
               break;
             }
           }
         }else {
           qh_makeridges(qh, neighbor);
           qh_setdel(neighbor->neighbors, same);
           /* same can't be horizon facet for neighbor */
         }
       }else { /* non-simplicial neighbor */
         qh_setdel(neighbor->neighbors, same);
         if (neighbor->visitid != qh->visit_id) {
           qh_setappend(qh, &neighbor->neighbors, newfacet);
           qh_setappend(qh, &newfacet->neighbors, neighbor);
           neighbor->visitid= qh->visit_id;
           newneighbors++;
         }
       }
     }
   }
   trace2((qh, qh->ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
              delneighbors, newneighbors));
 } /* mergecycle_neighbors */
 
 /*---------------------------------
 
   qh_mergecycle_ridges(qh, samecycle, newfacet )
     add ridges/neighbors for facets in samecycle to newfacet
     all new/old neighbors of newfacet marked with qh.visit_id
     facets in samecycle marked with qh.visit_id-1
     newfacet marked with qh.visit_id
 
   returns:
     newfacet has merged ridges
 
   notes:
     ridge already updated for simplicial neighbors of samecycle with a ridge
 
   see:
     qh_mergeridges()
     qh_makeridges()
 
   design:
     remove ridges between newfacet and samecycle
     for each facet in samecycle
       for each ridge in facet
         update facet pointers in ridge
         skip ridges processed in qh_mergecycle_neighors
         free ridges between newfacet and samecycle
         free ridges between facets of samecycle (on 2nd visit)
         append remaining ridges to newfacet
       if simpilicial facet
         for each neighbor of facet
           if simplicial facet
           and not samecycle facet or newfacet
             make ridge between neighbor and newfacet
 */
 void qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet) {
   facetT *same, *neighbor= NULL;
   int numold=0, numnew=0;
   int neighbor_i, neighbor_n;
   unsigned int samevisitid;
   ridgeT *ridge, **ridgep;
   boolT toporient;
   void **freelistp; /* used !qh_NOmem */
 
   trace4((qh, qh->ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));
   samevisitid= qh->visit_id -1;
   FOREACHridge_(newfacet->ridges) {
     neighbor= otherfacet_(ridge, newfacet);
     if (neighbor->visitid == samevisitid)
       SETref_(ridge)= NULL; /* ridge free'd below */
   }
   qh_setcompact(qh, newfacet->ridges);
 
   trace4((qh, qh->ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));
   FORALLsame_cycle_(samecycle) {
     FOREACHridge_(same->ridges) {
       if (ridge->top == same) {
         ridge->top= newfacet;
         neighbor= ridge->bottom;
       }else if (ridge->bottom == same) {
         ridge->bottom= newfacet;
         neighbor= ridge->top;
       }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
         qh_setappend(qh, &newfacet->ridges, ridge);
         numold++;  /* already set by qh_mergecycle_neighbors */
         continue;
       }else {
         qh_fprintf(qh, qh->ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
         qh_errexit(qh, qh_ERRqhull, NULL, ridge);
       }
       if (neighbor == newfacet) {
         qh_setfree(qh, &(ridge->vertices));
         qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
         numold++;
       }else if (neighbor->visitid == samevisitid) {
         qh_setdel(neighbor->ridges, ridge);
         qh_setfree(qh, &(ridge->vertices));
         qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
         numold++;
       }else {
         qh_setappend(qh, &newfacet->ridges, ridge);
         numold++;
       }
     }
     if (same->ridges)
       qh_settruncate(qh, same->ridges, 0);
     if (!same->simplicial)
       continue;
     FOREACHneighbor_i_(qh, same) {       /* note: !newfact->simplicial */
       if (neighbor->visitid != samevisitid && neighbor->simplicial) {
         ridge= qh_newridge(qh);
         ridge->vertices= qh_setnew_delnthsorted(qh, same->vertices, qh->hull_dim,
                                                           neighbor_i, 0);
         toporient= same->toporient ^ (neighbor_i & 0x1);
         if (toporient) {
           ridge->top= newfacet;
           ridge->bottom= neighbor;
         }else {
           ridge->top= neighbor;
           ridge->bottom= newfacet;
         }
         qh_setappend(qh, &(newfacet->ridges), ridge);
         qh_setappend(qh, &(neighbor->ridges), ridge);
         numnew++;
       }
     }
   }
 
   trace2((qh, qh->ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
              numold, numnew));
 } /* mergecycle_ridges */
 
 /*---------------------------------
 
   qh_mergecycle_vneighbors(qh, samecycle, newfacet )
     create vertex neighbors for newfacet from vertices of facets in samecycle
     samecycle marked with visitid == qh.visit_id - 1
 
   returns:
     newfacet vertices with updated neighbors
     marks newfacet with qh.visit_id-1
     deletes vertices that are merged away
     sets delridge on all vertices (faster here than in mergecycle_ridges)
 
   see:
     qh_mergevertex_neighbors()
 
   design:
     for each vertex of samecycle facet
       set vertex->delridge
       delete samecycle facets from vertex neighbors
       append newfacet to vertex neighbors
       if vertex only in newfacet
         delete it from newfacet
         add it to qh.del_vertices for later deletion
 */
 void qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
   facetT *neighbor, **neighborp;
   unsigned int mergeid;
   vertexT *vertex, **vertexp, *apex;
   setT *vertices;
 
   trace4((qh, qh->ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));
   mergeid= qh->visit_id - 1;
   newfacet->visitid= mergeid;
   vertices= qh_basevertices(qh, samecycle); /* temp */
   apex= SETfirstt_(samecycle->vertices, vertexT);
   qh_setappend(qh, &vertices, apex);
   FOREACHvertex_(vertices) {
     vertex->delridge= True;
     FOREACHneighbor_(vertex) {
       if (neighbor->visitid == mergeid)
         SETref_(neighbor)= NULL;
     }
     qh_setcompact(qh, vertex->neighbors);
     qh_setappend(qh, &vertex->neighbors, newfacet);
     if (!SETsecond_(vertex->neighbors)) {
       zinc_(Zcyclevertex);
       trace2((qh, qh->ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
         vertex->id, samecycle->id, newfacet->id));
       qh_setdelsorted(newfacet->vertices, vertex);
       vertex->deleted= True;
       qh_setappend(qh, &qh->del_vertices, vertex);
     }
   }
   qh_settempfree(qh, &vertices);
   trace3((qh, qh->ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
              samecycle->id, newfacet->id));
 } /* mergecycle_vneighbors */
 
 /*---------------------------------
 
   qh_mergefacet(qh, facet1, facet2, mindist, maxdist, mergeapex )
     merges facet1 into facet2
     mergeapex==qh_MERGEapex if merging new facet into coplanar horizon
 
   returns:
     qh.max_outside and qh.min_vertex updated
     initializes vertex neighbors on first merge
 
   returns:
     facet2 contains facet1's vertices, neighbors, and ridges
       facet2 moved to end of qh.facet_list
       makes facet2 a newfacet
       sets facet2->newmerge set
       clears facet2->center (unless merging into a large facet)
       clears facet2->tested and ridge->tested for facet1
 
     facet1 prepended to visible_list for later deletion and partitioning
       facet1->f.replace == facet2
 
     adds neighboring facets to facet_mergeset if redundant or degenerate
 
   notes:
     mindist/maxdist may be NULL (only if both NULL)
     traces merge if fmax_(maxdist,-mindist) > TRACEdist
 
   see:
     qh_mergecycle()
 
   design:
     trace merge and check for degenerate simplex
     make ridges for both facets
     update qh.max_outside, qh.max_vertex, qh.min_vertex
     update facet2->maxoutside and keepcentrum
     update facet2->nummerge
     update tested flags for facet2
     if facet1 is simplicial
       merge facet1 into facet2
     else
       merge facet1's neighbors into facet2
       merge facet1's ridges into facet2
       merge facet1's vertices into facet2
       merge facet1's vertex neighbors into facet2
       add facet2's vertices to qh.new_vertexlist
       unless qh_MERGEapex
         test facet2 for degenerate or redundant neighbors
       move facet1 to qh.visible_list for later deletion
       move facet2 to end of qh.newfacet_list
 */
 void qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {
   boolT traceonce= False;
   vertexT *vertex, **vertexp;
   int tracerestore=0, nummerge;
 
   if (facet1->tricoplanar || facet2->tricoplanar) {
     if (!qh->TRInormals) {
       qh_fprintf(qh, qh->ferr, 6226, "Qhull internal error (qh_mergefacet): does not work for tricoplanar facets.  Use option 'Q11'\n");
       qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
     }
     if (facet2->tricoplanar) {
       facet2->tricoplanar= False;
       facet2->keepcentrum= False;
     }
   }
   zzinc_(Ztotmerge);
   if (qh->REPORTfreq2 && qh->POSTmerging) {
     if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
       qh_tracemerging(qh);
   }
 #ifndef qh_NOtrace
   if (qh->build_cnt >= qh->RERUN) {
     if (mindist && (-*mindist > qh->TRACEdist || *maxdist > qh->TRACEdist)) {
       tracerestore= 0;
       qh->IStracing= qh->TRACElevel;
       traceonce= True;
       qh_fprintf(qh, qh->ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),
              fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh->furthest_id);
     }else if (facet1 == qh->tracefacet || facet2 == qh->tracefacet) {
       tracerestore= qh->IStracing;
       qh->IStracing= 4;
       traceonce= True;
       qh_fprintf(qh, qh->ferr, 8076, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",
                  zzval_(Ztotmerge), qh->tracefacet_id,  qh->furthest_id);
     }
   }
   if (qh->IStracing >= 2) {
     realT mergemin= -2;
     realT mergemax= -2;
 
     if (mindist) {
       mergemin= *mindist;
       mergemax= *maxdist;
     }
     qh_fprintf(qh, qh->ferr, 8077, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n",
     zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);
   }
 #endif /* !qh_NOtrace */
   if (facet1 == facet2 || facet1->visible || facet2->visible) {
     qh_fprintf(qh, qh->ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",
              facet1->id, facet2->id);
     qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
   }
   if (qh->num_facets - qh->num_visible <= qh->hull_dim + 1) {
     qh_fprintf(qh, qh->ferr, 6227, "\n\
 qhull precision error: Only %d facets remain.  Can not merge another\n\
 pair.  The input is too degenerate or the convexity constraints are\n\
 too strong.\n", qh->hull_dim+1);
     if (qh->hull_dim >= 5 && !qh->MERGEexact)
       qh_fprintf(qh, qh->ferr, 8079, "Option 'Qx' may avoid this problem.\n");
     qh_errexit(qh, qh_ERRprec, NULL, NULL);
   }
   if (!qh->VERTEXneighbors)
     qh_vertexneighbors(qh);
   qh_makeridges(qh, facet1);
   qh_makeridges(qh, facet2);
   if (qh->IStracing >=4)
     qh_errprint(qh, "MERGING", facet1, facet2, NULL, NULL);
   if (mindist) {
     maximize_(qh->max_outside, *maxdist);
     maximize_(qh->max_vertex, *maxdist);
 #if qh_MAXoutside
     maximize_(facet2->maxoutside, *maxdist);
 #endif
     minimize_(qh->min_vertex, *mindist);
     if (!facet2->keepcentrum
     && (*maxdist > qh->WIDEfacet || *mindist < -qh->WIDEfacet)) {
       facet2->keepcentrum= True;
       zinc_(Zwidefacet);
     }
   }
   nummerge= facet1->nummerge + facet2->nummerge + 1;
   if (nummerge >= qh_MAXnummerge)
     facet2->nummerge= qh_MAXnummerge;
   else
     facet2->nummerge= (short unsigned int)nummerge;
   facet2->newmerge= True;
   facet2->dupridge= False;
   qh_updatetested(qh, facet1, facet2);
   if (qh->hull_dim > 2 && qh_setsize(qh, facet1->vertices) == qh->hull_dim)
     qh_mergesimplex(qh, facet1, facet2, mergeapex);
   else {
     qh->vertex_visit++;
     FOREACHvertex_(facet2->vertices)
       vertex->visitid= qh->vertex_visit;
     if (qh->hull_dim == 2)
       qh_mergefacet2d(qh, facet1, facet2);
     else {
       qh_mergeneighbors(qh, facet1, facet2);
       qh_mergevertices(qh, facet1->vertices, &facet2->vertices);
     }
     qh_mergeridges(qh, facet1, facet2);
     qh_mergevertex_neighbors(qh, facet1, facet2);
     if (!facet2->newfacet)
       qh_newvertices(qh, facet2->vertices);
   }
   if (!mergeapex)
     qh_degen_redundant_neighbors(qh, facet2, facet1);
   if (facet2->coplanar || !facet2->newfacet) {
     zinc_(Zmergeintohorizon);
   }else if (!facet1->newfacet && facet2->newfacet) {
     zinc_(Zmergehorizon);
   }else {
     zinc_(Zmergenew);
   }
   qh_willdelete(qh, facet1, facet2);
   qh_removefacet(qh, facet2);  /* append as a newfacet to end of qh->facet_list */
   qh_appendfacet(qh, facet2);
   facet2->newfacet= True;
   facet2->tested= False;
   qh_tracemerge(qh, facet1, facet2);
   if (traceonce) {
     qh_fprintf(qh, qh->ferr, 8080, "qh_mergefacet: end of wide tracing\n");
     qh->IStracing= tracerestore;
   }
 } /* mergefacet */
 
 
 /*---------------------------------
 
   qh_mergefacet2d(qh, facet1, facet2 )
     in 2d, merges neighbors and vertices of facet1 into facet2
 
   returns:
     build ridges for neighbors if necessary
     facet2 looks like a simplicial facet except for centrum, ridges
       neighbors are opposite the corresponding vertex
       maintains orientation of facet2
 
   notes:
     qh_mergefacet() retains non-simplicial structures
       they are not needed in 2d, but later routines may use them
     preserves qh.vertex_visit for qh_mergevertex_neighbors()
 
   design:
     get vertices and neighbors
     determine new vertices and neighbors
     set new vertices and neighbors and adjust orientation
     make ridges for new neighbor if needed
 */
 void qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2) {
   vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
   facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
 
   vertex1A= SETfirstt_(facet1->vertices, vertexT);
   vertex1B= SETsecondt_(facet1->vertices, vertexT);
   vertex2A= SETfirstt_(facet2->vertices, vertexT);
   vertex2B= SETsecondt_(facet2->vertices, vertexT);
   neighbor1A= SETfirstt_(facet1->neighbors, facetT);
   neighbor1B= SETsecondt_(facet1->neighbors, facetT);
   neighbor2A= SETfirstt_(facet2->neighbors, facetT);
   neighbor2B= SETsecondt_(facet2->neighbors, facetT);
   if (vertex1A == vertex2A) {
     vertexA= vertex1B;
     vertexB= vertex2B;
     neighborA= neighbor2A;
     neighborB= neighbor1A;
   }else if (vertex1A == vertex2B) {
     vertexA= vertex1B;
     vertexB= vertex2A;
     neighborA= neighbor2B;
     neighborB= neighbor1A;
   }else if (vertex1B == vertex2A) {
     vertexA= vertex1A;
     vertexB= vertex2B;
     neighborA= neighbor2A;
     neighborB= neighbor1B;
   }else { /* 1B == 2B */
     vertexA= vertex1A;
     vertexB= vertex2A;
     neighborA= neighbor2B;
     neighborB= neighbor1B;
   }
   /* vertexB always from facet2, neighborB always from facet1 */
   if (vertexA->id > vertexB->id) {
     SETfirst_(facet2->vertices)= vertexA;
     SETsecond_(facet2->vertices)= vertexB;
     if (vertexB == vertex2A)
       facet2->toporient= !facet2->toporient;
     SETfirst_(facet2->neighbors)= neighborA;
     SETsecond_(facet2->neighbors)= neighborB;
   }else {
     SETfirst_(facet2->vertices)= vertexB;
     SETsecond_(facet2->vertices)= vertexA;
     if (vertexB == vertex2B)
       facet2->toporient= !facet2->toporient;
     SETfirst_(facet2->neighbors)= neighborB;
     SETsecond_(facet2->neighbors)= neighborA;
   }
   qh_makeridges(qh, neighborB);
   qh_setreplace(qh, neighborB->neighbors, facet1, facet2);
   trace4((qh, qh->ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
        vertexA->id, neighborB->id, facet1->id, facet2->id));
 } /* mergefacet2d */
 
 
 /*---------------------------------
 
   qh_mergeneighbors(qh, facet1, facet2 )
     merges the neighbors of facet1 into facet2
 
   see:
     qh_mergecycle_neighbors()
 
   design:
     for each neighbor of facet1
       if neighbor is also a neighbor of facet2
         if neighbor is simpilicial
           make ridges for later deletion as a degenerate facet
         update its neighbor set
       else
         move the neighbor relation to facet2
     remove the neighbor relation for facet1 and facet2
 */
 void qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2) {
   facetT *neighbor, **neighborp;
 
   trace4((qh, qh->ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
           facet1->id, facet2->id));
   qh->visit_id++;
   FOREACHneighbor_(facet2) {
     neighbor->visitid= qh->visit_id;
   }
   FOREACHneighbor_(facet1) {
     if (neighbor->visitid == qh->visit_id) {
       if (neighbor->simplicial)    /* is degen, needs ridges */
         qh_makeridges(qh, neighbor);
       if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
         qh_setdel(neighbor->neighbors, facet1);
       else {
         qh_setdel(neighbor->neighbors, facet2);
         qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
       }
     }else if (neighbor != facet2) {
       qh_setappend(qh, &(facet2->neighbors), neighbor);
       qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
     }
   }
   qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
   qh_setdel(facet2->neighbors, facet1);
 } /* mergeneighbors */
 
 
 /*---------------------------------
 
   qh_mergeridges(qh, facet1, facet2 )
     merges the ridge set of facet1 into facet2
 
   returns:
     may delete all ridges for a vertex
     sets vertex->delridge on deleted ridges
 
   see:
     qh_mergecycle_ridges()
 
   design:
     delete ridges between facet1 and facet2
       mark (delridge) vertices on these ridges for later testing
     for each remaining ridge
       rename facet1 to facet2
 */
 void qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2) {
   ridgeT *ridge, **ridgep;
   vertexT *vertex, **vertexp;
 
   trace4((qh, qh->ferr, 4038, "qh_mergeridges: merge ridges of f%d and f%d\n",
           facet1->id, facet2->id));
   FOREACHridge_(facet2->ridges) {
     if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
       FOREACHvertex_(ridge->vertices)
         vertex->delridge= True;
       qh_delridge(qh, ridge);  /* expensive in high-d, could rebuild */
       ridgep--; /*repeat*/
     }
   }
   FOREACHridge_(facet1->ridges) {
     if (ridge->top == facet1)
       ridge->top= facet2;
     else
       ridge->bottom= facet2;
     qh_setappend(qh, &(facet2->ridges), ridge);
   }
 } /* mergeridges */
 
 
 /*---------------------------------
 
   qh_mergesimplex(qh, facet1, facet2, mergeapex )
     merge simplicial facet1 into facet2
     mergeapex==qh_MERGEapex if merging samecycle into horizon facet
       vertex id is latest (most recently created)
     facet1 may be contained in facet2
     ridges exist for both facets
 
   returns:
     facet2 with updated vertices, ridges, neighbors
     updated neighbors for facet1's vertices
     facet1 not deleted
     sets vertex->delridge on deleted ridges
 
   notes:
     special case code since this is the most common merge
     called from qh_mergefacet()
 
   design:
     if qh_MERGEapex
       add vertices of facet2 to qh.new_vertexlist if necessary
       add apex to facet2
     else
       for each ridge between facet1 and facet2
         set vertex->delridge
       determine the apex for facet1 (i.e., vertex to be merged)
       unless apex already in facet2
         insert apex into vertices for facet2
       add vertices of facet2 to qh.new_vertexlist if necessary
       add apex to qh.new_vertexlist if necessary
       for each vertex of facet1
         if apex
           rename facet1 to facet2 in its vertex neighbors
         else
           delete facet1 from vertex neighors
           if only in facet2
             add vertex to qh.del_vertices for later deletion
       for each ridge of facet1
         delete ridges between facet1 and facet2
         append other ridges to facet2 after renaming facet to facet2
 */
 void qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex) {
   vertexT *vertex, **vertexp, *apex;
   ridgeT *ridge, **ridgep;
   boolT issubset= False;
   int vertex_i= -1, vertex_n;
   facetT *neighbor, **neighborp, *otherfacet;
 
   if (mergeapex) {
     if (!facet2->newfacet)
       qh_newvertices(qh, facet2->vertices);  /* apex is new */
     apex= SETfirstt_(facet1->vertices, vertexT);
     if (SETfirstt_(facet2->vertices, vertexT) != apex)
       qh_setaddnth(qh, &facet2->vertices, 0, apex);  /* apex has last id */
     else
       issubset= True;
   }else {
     zinc_(Zmergesimplex);
     FOREACHvertex_(facet1->vertices)
       vertex->seen= False;
     FOREACHridge_(facet1->ridges) {
       if (otherfacet_(ridge, facet1) == facet2) {
         FOREACHvertex_(ridge->vertices) {
           vertex->seen= True;
           vertex->delridge= True;
         }
         break;
       }
     }
     FOREACHvertex_(facet1->vertices) {
       if (!vertex->seen)
         break;  /* must occur */
     }
     apex= vertex;
     trace4((qh, qh->ferr, 4039, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
           apex->id, facet1->id, facet2->id));
     FOREACHvertex_i_(qh, facet2->vertices) {
       if (vertex->id < apex->id) {
         break;
       }else if (vertex->id == apex->id) {
         issubset= True;
         break;
       }
     }
     if (!issubset)
       qh_setaddnth(qh, &facet2->vertices, vertex_i, apex);
     if (!facet2->newfacet)
       qh_newvertices(qh, facet2->vertices);
     else if (!apex->newlist) {
       qh_removevertex(qh, apex);
       qh_appendvertex(qh, apex);
     }
   }
   trace4((qh, qh->ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",
           facet1->id));
   FOREACHvertex_(facet1->vertices) {
     if (vertex == apex && !issubset)
       qh_setreplace(qh, vertex->neighbors, facet1, facet2);
     else {
       qh_setdel(vertex->neighbors, facet1);
       if (!SETsecond_(vertex->neighbors))
         qh_mergevertex_del(qh, vertex, facet1, facet2);
     }
   }
   trace4((qh, qh->ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
           facet1->id, facet2->id));
   qh->visit_id++;
   FOREACHneighbor_(facet2)
     neighbor->visitid= qh->visit_id;
   FOREACHridge_(facet1->ridges) {
     otherfacet= otherfacet_(ridge, facet1);
     if (otherfacet == facet2) {
       qh_setdel(facet2->ridges, ridge);
       qh_setfree(qh, &(ridge->vertices));
       qh_memfree(qh, ridge, (int)sizeof(ridgeT));
       qh_setdel(facet2->neighbors, facet1);
     }else {
       qh_setappend(qh, &facet2->ridges, ridge);
       if (otherfacet->visitid != qh->visit_id) {
         qh_setappend(qh, &facet2->neighbors, otherfacet);
         qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
         otherfacet->visitid= qh->visit_id;
       }else {
         if (otherfacet->simplicial)    /* is degen, needs ridges */
           qh_makeridges(qh, otherfacet);
         if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)
           qh_setdel(otherfacet->neighbors, facet1);
         else {   /*keep newfacet->neighbors->horizon*/
           qh_setdel(otherfacet->neighbors, facet2);
           qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
         }
       }
       if (ridge->top == facet1) /* wait until after qh_makeridges */
         ridge->top= facet2;
       else
         ridge->bottom= facet2;
     }
   }
   SETfirst_(facet1->ridges)= NULL; /* it will be deleted */
   trace3((qh, qh->ferr, 3006, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",
           facet1->id, getid_(apex), facet2->id));
 } /* mergesimplex */
 
 /*---------------------------------
 
   qh_mergevertex_del(qh, vertex, facet1, facet2 )
     delete a vertex because of merging facet1 into facet2
 
   returns:
     deletes vertex from facet2
     adds vertex to qh.del_vertices for later deletion
 */
 void qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2) {
 
   zinc_(Zmergevertex);
   trace2((qh, qh->ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
           vertex->id, facet1->id, facet2->id));
   qh_setdelsorted(facet2->vertices, vertex);
   vertex->deleted= True;
   qh_setappend(qh, &qh->del_vertices, vertex);
 } /* mergevertex_del */
 
 /*---------------------------------
 
   qh_mergevertex_neighbors(qh, facet1, facet2 )
     merge the vertex neighbors of facet1 to facet2
 
   returns:
     if vertex is current qh.vertex_visit
       deletes facet1 from vertex->neighbors
     else
       renames facet1 to facet2 in vertex->neighbors
     deletes vertices if only one neighbor
 
   notes:
     assumes vertex neighbor sets are good
 */
 void qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2) {
   vertexT *vertex, **vertexp;
 
   trace4((qh, qh->ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
           facet1->id, facet2->id));
   if (qh->tracevertex) {
     qh_fprintf(qh, qh->ferr, 8081, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",
              facet1->id, facet2->id, qh->furthest_id, qh->tracevertex->neighbors->e[0].p);
     qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
   }
   FOREACHvertex_(facet1->vertices) {
     if (vertex->visitid != qh->vertex_visit)
       qh_setreplace(qh, vertex->neighbors, facet1, facet2);
     else {
       qh_setdel(vertex->neighbors, facet1);
       if (!SETsecond_(vertex->neighbors))
         qh_mergevertex_del(qh, vertex, facet1, facet2);
     }
   }
   if (qh->tracevertex)
     qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
 } /* mergevertex_neighbors */
 
 
 /*---------------------------------
 
   qh_mergevertices(qh, vertices1, vertices2 )
     merges the vertex set of facet1 into facet2
 
   returns:
     replaces vertices2 with merged set
     preserves vertex_visit for qh_mergevertex_neighbors
     updates qh.newvertex_list
 
   design:
     create a merged set of both vertices (in inverse id order)
 */
 void qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices2) {
   int newsize= qh_setsize(qh, vertices1)+qh_setsize(qh, *vertices2) - qh->hull_dim + 1;
   setT *mergedvertices;
   vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
 
   mergedvertices= qh_settemp(qh, newsize);
   FOREACHvertex_(vertices1) {
     if (!*vertex2 || vertex->id > (*vertex2)->id)
       qh_setappend(qh, &mergedvertices, vertex);
     else {
       while (*vertex2 && (*vertex2)->id > vertex->id)
         qh_setappend(qh, &mergedvertices, *vertex2++);
       if (!*vertex2 || (*vertex2)->id < vertex->id)
         qh_setappend(qh, &mergedvertices, vertex);
       else
         qh_setappend(qh, &mergedvertices, *vertex2++);
     }
   }
   while (*vertex2)
     qh_setappend(qh, &mergedvertices, *vertex2++);
   if (newsize < qh_setsize(qh, mergedvertices)) {
     qh_fprintf(qh, qh->ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   qh_setfree(qh, vertices2);
   *vertices2= mergedvertices;
   qh_settemppop(qh);
 } /* mergevertices */
 
 
 /*---------------------------------
 
   qh_neighbor_intersections(qh, vertex )
     return intersection of all vertices in vertex->neighbors except for vertex
 
   returns:
     returns temporary set of vertices
     does not include vertex
     NULL if a neighbor is simplicial
     NULL if empty set
 
   notes:
     used for renaming vertices
 
   design:
     initialize the intersection set with vertices of the first two neighbors
     delete vertex from the intersection
     for each remaining neighbor
       intersect its vertex set with the intersection set
       return NULL if empty
     return the intersection set
 */
 setT *qh_neighbor_intersections(qhT *qh, vertexT *vertex) {
   facetT *neighbor, **neighborp, *neighborA, *neighborB;
   setT *intersect;
   int neighbor_i, neighbor_n;
 
   FOREACHneighbor_(vertex) {
     if (neighbor->simplicial)
       return NULL;
   }
   neighborA= SETfirstt_(vertex->neighbors, facetT);
   neighborB= SETsecondt_(vertex->neighbors, facetT);
   zinc_(Zintersectnum);
   if (!neighborA)
     return NULL;
   if (!neighborB)
     intersect= qh_setcopy(qh, neighborA->vertices, 0);
   else
     intersect= qh_vertexintersect_new(qh, neighborA->vertices, neighborB->vertices);
   qh_settemppush(qh, intersect);
   qh_setdelsorted(intersect, vertex);
   FOREACHneighbor_i_(qh, vertex) {
     if (neighbor_i >= 2) {
       zinc_(Zintersectnum);
       qh_vertexintersect(qh, &intersect, neighbor->vertices);
       if (!SETfirst_(intersect)) {
         zinc_(Zintersectfail);
         qh_settempfree(qh, &intersect);
         return NULL;
       }
     }
   }
   trace3((qh, qh->ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
           qh_setsize(qh, intersect), vertex->id));
   return intersect;
 } /* neighbor_intersections */
 
 /*---------------------------------
 
   qh_newvertices(qh, vertices )
     add vertices to end of qh.vertex_list (marks as new vertices)
 
   returns:
     vertices on qh.newvertex_list
     vertex->newlist set
 */
 void qh_newvertices(qhT *qh, setT *vertices) {
   vertexT *vertex, **vertexp;
 
   FOREACHvertex_(vertices) {
     if (!vertex->newlist) {
       qh_removevertex(qh, vertex);
       qh_appendvertex(qh, vertex);
     }
   }
 } /* newvertices */
 
 /*---------------------------------
 
   qh_reducevertices(qh)
     reduce extra vertices, shared vertices, and redundant vertices
     facet->newmerge is set if merged since last call
     if !qh.MERGEvertices, only removes extra vertices
 
   returns:
     True if also merged degen_redundant facets
     vertices are renamed if possible
     clears facet->newmerge and vertex->delridge
 
   notes:
     ignored if 2-d
 
   design:
     merge any degenerate or redundant facets
     for each newly merged facet
       remove extra vertices
     if qh.MERGEvertices
       for each newly merged facet
         for each vertex
           if vertex was on a deleted ridge
             rename vertex if it is shared
       remove delridge flag from new vertices
 */
 boolT qh_reducevertices(qhT *qh) {
   int numshare=0, numrename= 0;
   boolT degenredun= False;
   facetT *newfacet;
   vertexT *vertex, **vertexp;
 
   if (qh->hull_dim == 2)
     return False;
   if (qh_merge_degenredundant(qh))
     degenredun= True;
  LABELrestart:
   FORALLnew_facets {
     if (newfacet->newmerge) {
       if (!qh->MERGEvertices)
         newfacet->newmerge= False;
       qh_remove_extravertices(qh, newfacet);
     }
   }
   if (!qh->MERGEvertices)
     return False;
   FORALLnew_facets {
     if (newfacet->newmerge) {
       newfacet->newmerge= False;
       FOREACHvertex_(newfacet->vertices) {
         if (vertex->delridge) {
           if (qh_rename_sharedvertex(qh, vertex, newfacet)) {
             numshare++;
             vertexp--; /* repeat since deleted vertex */
           }
         }
       }
     }
   }
   FORALLvertex_(qh->newvertex_list) {
     if (vertex->delridge && !vertex->deleted) {
       vertex->delridge= False;
       if (qh->hull_dim >= 4 && qh_redundant_vertex(qh, vertex)) {
         numrename++;
         if (qh_merge_degenredundant(qh)) {
           degenredun= True;
           goto LABELrestart;
         }
       }
     }
   }
   trace1((qh, qh->ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
           numshare, numrename, degenredun));
   return degenredun;
 } /* reducevertices */
 
 /*---------------------------------
 
   qh_redundant_vertex(qh, vertex )
     detect and rename a redundant vertex
     vertices have full vertex->neighbors
 
   returns:
     returns true if find a redundant vertex
       deletes vertex(vertex->deleted)
 
   notes:
     only needed if vertex->delridge and hull_dim >= 4
     may add degenerate facets to qh.facet_mergeset
     doesn't change vertex->neighbors or create redundant facets
 
   design:
     intersect vertices of all facet neighbors of vertex
     determine ridges for these vertices
     if find a new vertex for vertex amoung these ridges and vertices
       rename vertex to the new vertex
 */
 vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex) {
   vertexT *newvertex= NULL;
   setT *vertices, *ridges;
 
   trace3((qh, qh->ferr, 3008, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));
   if ((vertices= qh_neighbor_intersections(qh, vertex))) {
     ridges= qh_vertexridges(qh, vertex);
     if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))
       qh_renamevertex(qh, vertex, newvertex, ridges, NULL, NULL);
     qh_settempfree(qh, &ridges);
     qh_settempfree(qh, &vertices);
   }
   return newvertex;
 } /* redundant_vertex */
 
 /*---------------------------------
 
   qh_remove_extravertices(qh, facet )
     remove extra vertices from non-simplicial facets
 
   returns:
     returns True if it finds them
 
   design:
     for each vertex in facet
       if vertex not in a ridge (i.e., no longer used)
         delete vertex from facet
         delete facet from vertice's neighbors
         unless vertex in another facet
           add vertex to qh.del_vertices for later deletion
 */
 boolT qh_remove_extravertices(qhT *qh, facetT *facet) {
   ridgeT *ridge, **ridgep;
   vertexT *vertex, **vertexp;
   boolT foundrem= False;
 
   trace4((qh, qh->ferr, 4043, "qh_remove_extravertices: test f%d for extra vertices\n",
           facet->id));
   FOREACHvertex_(facet->vertices)
     vertex->seen= False;
   FOREACHridge_(facet->ridges) {
     FOREACHvertex_(ridge->vertices)
       vertex->seen= True;
   }
   FOREACHvertex_(facet->vertices) {
     if (!vertex->seen) {
       foundrem= True;
       zinc_(Zremvertex);
       qh_setdelsorted(facet->vertices, vertex);
       qh_setdel(vertex->neighbors, facet);
       if (!qh_setsize(qh, vertex->neighbors)) {
         vertex->deleted= True;
         qh_setappend(qh, &qh->del_vertices, vertex);
         zinc_(Zremvertexdel);
         trace2((qh, qh->ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
       }else
         trace3((qh, qh->ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
       vertexp--; /*repeat*/
     }
   }
   return foundrem;
 } /* remove_extravertices */
 
 /*---------------------------------
 
   qh_rename_sharedvertex(qh, vertex, facet )
     detect and rename if shared vertex in facet
     vertices have full ->neighbors
 
   returns:
     newvertex or NULL
     the vertex may still exist in other facets (i.e., a neighbor was pinched)
     does not change facet->neighbors
     updates vertex->neighbors
 
   notes:
     a shared vertex for a facet is only in ridges to one neighbor
     this may undo a pinched facet
 
     it does not catch pinches involving multiple facets.  These appear
       to be difficult to detect, since an exhaustive search is too expensive.
 
   design:
     if vertex only has two neighbors
       determine the ridges that contain the vertex
       determine the vertices shared by both neighbors
       if can find a new vertex in this set
         rename the vertex to the new vertex
 */
 vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet) {
   facetT *neighbor, **neighborp, *neighborA= NULL;
   setT *vertices, *ridges;
   vertexT *newvertex;
 
   if (qh_setsize(qh, vertex->neighbors) == 2) {
     neighborA= SETfirstt_(vertex->neighbors, facetT);
     if (neighborA == facet)
       neighborA= SETsecondt_(vertex->neighbors, facetT);
   }else if (qh->hull_dim == 3)
     return NULL;
   else {
     qh->visit_id++;
     FOREACHneighbor_(facet)
       neighbor->visitid= qh->visit_id;
     FOREACHneighbor_(vertex) {
       if (neighbor->visitid == qh->visit_id) {
         if (neighborA)
           return NULL;
         neighborA= neighbor;
       }
     }
     if (!neighborA) {
       qh_fprintf(qh, qh->ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
         vertex->id, facet->id);
       qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, vertex);
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     }
   }
   /* the vertex is shared by facet and neighborA */
   ridges= qh_settemp(qh, qh->TEMPsize);
   neighborA->visitid= ++qh->visit_id;
   qh_vertexridges_facet(qh, vertex, facet, &ridges);
   trace2((qh, qh->ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",
     qh_pointid(qh, vertex->point), vertex->id, facet->id, qh_setsize(qh, ridges), neighborA->id));
   zinc_(Zintersectnum);
   vertices= qh_vertexintersect_new(qh, facet->vertices, neighborA->vertices);
   qh_setdel(vertices, vertex);
   qh_settemppush(qh, vertices);
   if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))
     qh_renamevertex(qh, vertex, newvertex, ridges, facet, neighborA);
   qh_settempfree(qh, &vertices);
   qh_settempfree(qh, &ridges);
   return newvertex;
 } /* rename_sharedvertex */
 
 /*---------------------------------
 
   qh_renameridgevertex(qh, ridge, oldvertex, newvertex )
     renames oldvertex as newvertex in ridge
 
   returns:
 
   design:
     delete oldvertex from ridge
     if newvertex already in ridge
       copy ridge->noconvex to another ridge if possible
       delete the ridge
     else
       insert newvertex into the ridge
       adjust the ridge's orientation
 */
 void qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
   int nth= 0, oldnth;
   facetT *temp;
   vertexT *vertex, **vertexp;
 
   oldnth= qh_setindex(ridge->vertices, oldvertex);
   qh_setdelnthsorted(qh, ridge->vertices, oldnth);
   FOREACHvertex_(ridge->vertices) {
     if (vertex == newvertex) {
       zinc_(Zdelridge);
       if (ridge->nonconvex) /* only one ridge has nonconvex set */
         qh_copynonconvex(qh, ridge);
       qh_delridge(qh, ridge);
       trace2((qh, qh->ferr, 2038, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
         ridge->id, oldvertex->id, newvertex->id));
       return;
     }
     if (vertex->id < newvertex->id)
       break;
     nth++;
   }
   qh_setaddnth(qh, &ridge->vertices, nth, newvertex);
   if (abs(oldnth - nth)%2) {
     trace3((qh, qh->ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
             ridge->id));
     temp= ridge->top;
     ridge->top= ridge->bottom;
     ridge->bottom= temp;
   }
 } /* renameridgevertex */
 
 
 /*---------------------------------
 
   qh_renamevertex(qh, oldvertex, newvertex, ridges, oldfacet, neighborA )
     renames oldvertex as newvertex in ridges
     gives oldfacet/neighborA if oldvertex is shared between two facets
 
   returns:
     oldvertex may still exist afterwards
 
 
   notes:
     can not change neighbors of newvertex (since it's a subset)
 
   design:
     for each ridge in ridges
       rename oldvertex to newvertex and delete degenerate ridges
     if oldfacet not defined
       for each neighbor of oldvertex
         delete oldvertex from neighbor's vertices
         remove extra vertices from neighbor
       add oldvertex to qh.del_vertices
     else if oldvertex only between oldfacet and neighborA
       delete oldvertex from oldfacet and neighborA
       add oldvertex to qh.del_vertices
     else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
       delete oldvertex from oldfacet
       delete oldfacet from oldvertice's neighbors
       remove extra vertices (e.g., oldvertex) from neighborA
 */
 void qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
   facetT *neighbor, **neighborp;
   ridgeT *ridge, **ridgep;
   boolT istrace= False;
 
   if (qh->IStracing >= 2 || oldvertex->id == qh->tracevertex_id ||
         newvertex->id == qh->tracevertex_id)
     istrace= True;
   FOREACHridge_(ridges)
     qh_renameridgevertex(qh, ridge, oldvertex, newvertex);
   if (!oldfacet) {
     zinc_(Zrenameall);
     if (istrace)
       qh_fprintf(qh, qh->ferr, 8082, "qh_renamevertex: renamed v%d to v%d in several facets\n",
                oldvertex->id, newvertex->id);
     FOREACHneighbor_(oldvertex) {
       qh_maydropneighbor(qh, neighbor);
       qh_setdelsorted(neighbor->vertices, oldvertex);
       if (qh_remove_extravertices(qh, neighbor))
         neighborp--; /* neighbor may be deleted */
     }
     if (!oldvertex->deleted) {
       oldvertex->deleted= True;
       qh_setappend(qh, &qh->del_vertices, oldvertex);
     }
   }else if (qh_setsize(qh, oldvertex->neighbors) == 2) {
     zinc_(Zrenameshare);
     if (istrace)
       qh_fprintf(qh, qh->ferr, 8083, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n",
                oldvertex->id, newvertex->id, oldfacet->id);
     FOREACHneighbor_(oldvertex)
       qh_setdelsorted(neighbor->vertices, oldvertex);
     oldvertex->deleted= True;
     qh_setappend(qh, &qh->del_vertices, oldvertex);
   }else {
     zinc_(Zrenamepinch);
     if (istrace || qh->IStracing)
       qh_fprintf(qh, qh->ferr, 8084, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n",
                oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
     qh_setdelsorted(oldfacet->vertices, oldvertex);
     qh_setdel(oldvertex->neighbors, oldfacet);
     qh_remove_extravertices(qh, neighborA);
   }
 } /* renamevertex */
 
 
 /*---------------------------------
 
   qh_test_appendmerge(qh, facet, neighbor )
     tests facet/neighbor for convexity
     appends to mergeset if non-convex
     if pre-merging,
       nop if qh.SKIPconvex, or qh.MERGEexact and coplanar
 
   returns:
     true if appends facet/neighbor to mergeset
     sets facet->center as needed
     does not change facet->seen
 
   design:
     if qh.cos_max is defined
       if the angle between facet normals is too shallow
         append an angle-coplanar merge to qh.mergeset
         return True
     make facet's centrum if needed
     if facet's centrum is above the neighbor
       set isconcave
     else
       if facet's centrum is not below the neighbor
         set iscoplanar
       make neighbor's centrum if needed
       if neighbor's centrum is above the facet
         set isconcave
       else if neighbor's centrum is not below the facet
         set iscoplanar
    if isconcave or iscoplanar
      get angle if needed
      append concave or coplanar merge to qh.mergeset
 */
 boolT qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor) {
   realT dist, dist2= -REALmax, angle= -REALmax;
   boolT isconcave= False, iscoplanar= False, okangle= False;
 
   if (qh->SKIPconvex && !qh->POSTmerging)
     return False;
   if ((!qh->MERGEexact || qh->POSTmerging) && qh->cos_max < REALmax/2) {
     angle= qh_getangle(qh, facet->normal, neighbor->normal);
     zinc_(Zangletests);
     if (angle > qh->cos_max) {
       zinc_(Zcoplanarangle);
       qh_appendmergeset(qh, facet, neighbor, MRGanglecoplanar, &angle);
       trace2((qh, qh->ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
          angle, facet->id, neighbor->id));
       return True;
     }else
       okangle= True;
   }
   if (!facet->center)
     facet->center= qh_getcentrum(qh, facet);
   zzinc_(Zcentrumtests);
   qh_distplane(qh, facet->center, neighbor, &dist);
   if (dist > qh->centrum_radius)
     isconcave= True;
   else {
     if (dist > -qh->centrum_radius)
       iscoplanar= True;
     if (!neighbor->center)
       neighbor->center= qh_getcentrum(qh, neighbor);
     zzinc_(Zcentrumtests);
     qh_distplane(qh, neighbor->center, facet, &dist2);
     if (dist2 > qh->centrum_radius)
       isconcave= True;
     else if (!iscoplanar && dist2 > -qh->centrum_radius)
       iscoplanar= True;
   }
   if (!isconcave && (!iscoplanar || (qh->MERGEexact && !qh->POSTmerging)))
     return False;
   if (!okangle && qh->ANGLEmerge) {
     angle= qh_getangle(qh, facet->normal, neighbor->normal);
     zinc_(Zangletests);
   }
   if (isconcave) {
     zinc_(Zconcaveridge);
     if (qh->ANGLEmerge)
       angle += qh_ANGLEconcave + 0.5;
     qh_appendmergeset(qh, facet, neighbor, MRGconcave, &angle);
     trace0((qh, qh->ferr, 18, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",
            facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
   }else /* iscoplanar */ {
     zinc_(Zcoplanarcentrum);
     qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, &angle);
     trace2((qh, qh->ferr, 2040, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
               facet->id, neighbor->id, dist, dist2, angle));
   }
   return True;
 } /* test_appendmerge */
 
 /*---------------------------------
 
   qh_test_vneighbors(qh)
     test vertex neighbors for convexity
     tests all facets on qh.newfacet_list
 
   returns:
     true if non-convex vneighbors appended to qh.facet_mergeset
     initializes vertex neighbors if needed
 
   notes:
     assumes all facet neighbors have been tested
     this can be expensive
     this does not guarantee that a centrum is below all facets
       but it is unlikely
     uses qh.visit_id
 
   design:
     build vertex neighbors if necessary
     for all new facets
       for all vertices
         for each unvisited facet neighbor of the vertex
           test new facet and neighbor for convexity
 */
 boolT qh_test_vneighbors(qhT *qh /* qh->newfacet_list */) {
   facetT *newfacet, *neighbor, **neighborp;
   vertexT *vertex, **vertexp;
   int nummerges= 0;
 
   trace1((qh, qh->ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
   if (!qh->VERTEXneighbors)
     qh_vertexneighbors(qh);
   FORALLnew_facets
     newfacet->seen= False;
   FORALLnew_facets {
     newfacet->seen= True;
     newfacet->visitid= qh->visit_id++;
     FOREACHneighbor_(newfacet)
       newfacet->visitid= qh->visit_id;
     FOREACHvertex_(newfacet->vertices) {
       FOREACHneighbor_(vertex) {
         if (neighbor->seen || neighbor->visitid == qh->visit_id)
           continue;
         if (qh_test_appendmerge(qh, newfacet, neighbor))
           nummerges++;
       }
     }
   }
   zadd_(Ztestvneighbor, nummerges);
   trace1((qh, qh->ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
            nummerges));
   return (nummerges > 0);
 } /* test_vneighbors */
 
 /*---------------------------------
 
   qh_tracemerge(qh, facet1, facet2 )
     print trace message after merge
 */
 void qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2) {
   boolT waserror= False;
 
 #ifndef qh_NOtrace
   if (qh->IStracing >= 4)
     qh_errprint(qh, "MERGED", facet2, NULL, NULL, NULL);
   if (facet2 == qh->tracefacet || (qh->tracevertex && qh->tracevertex->newlist)) {
     qh_fprintf(qh, qh->ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh->furthest_id);
     if (facet2 != qh->tracefacet)
       qh_errprint(qh, "TRACE", qh->tracefacet,
         (qh->tracevertex && qh->tracevertex->neighbors) ?
            SETfirstt_(qh->tracevertex->neighbors, facetT) : NULL,
         NULL, qh->tracevertex);
   }
   if (qh->tracevertex) {
     if (qh->tracevertex->deleted)
       qh_fprintf(qh, qh->ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
             qh->furthest_id);
     else
       qh_checkvertex(qh, qh->tracevertex);
   }
   if (qh->tracefacet) {
     qh_checkfacet(qh, qh->tracefacet, True, &waserror);
     if (waserror)
       qh_errexit(qh, qh_ERRqhull, qh->tracefacet, NULL);
   }
 #endif /* !qh_NOtrace */
   if (qh->CHECKfrequently || qh->IStracing >= 4) { /* can't check polygon here */
     qh_checkfacet(qh, facet2, True, &waserror);
     if (waserror)
       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
 } /* tracemerge */
 
 /*---------------------------------
 
   qh_tracemerging(qh)
     print trace message during POSTmerging
 
   returns:
     updates qh.mergereport
 
   notes:
     called from qh_mergecycle() and qh_mergefacet()
 
   see:
     qh_buildtracing()
 */
 void qh_tracemerging(qhT *qh) {
   realT cpu;
   int total;
   time_t timedata;
   struct tm *tp;
 
   qh->mergereport= zzval_(Ztotmerge);
   time(&timedata);
   tp= localtime(&timedata);
   cpu= qh_CPUclock;
   cpu /= qh_SECticks;
   total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
   qh_fprintf(qh, qh->ferr, 8087, "\n\
 At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets.  The hull\n\
   contains %d facets and %d vertices.\n",
       tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,
       total, qh->num_facets - qh->num_visible,
       qh->num_vertices-qh_setsize(qh, qh->del_vertices));
 } /* tracemerging */
 
 /*---------------------------------
 
   qh_updatetested(qh, facet1, facet2 )
     clear facet2->tested and facet1->ridge->tested for merge
 
   returns:
     deletes facet2->center unless it's already large
       if so, clears facet2->ridge->tested
 
   design:
     clear facet2->tested
     clear ridge->tested for facet1's ridges
     if facet2 has a centrum
       if facet2 is large
         set facet2->keepcentrum
       else if facet2 has 3 vertices due to many merges, or not large and post merging
         clear facet2->keepcentrum
       unless facet2->keepcentrum
         clear facet2->center to recompute centrum later
         clear ridge->tested for facet2's ridges
 */
 void qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2) {
   ridgeT *ridge, **ridgep;
   int size;
 
   facet2->tested= False;
   FOREACHridge_(facet1->ridges)
     ridge->tested= False;
   if (!facet2->center)
     return;
   size= qh_setsize(qh, facet2->vertices);
   if (!facet2->keepcentrum) {
     if (size > qh->hull_dim + qh_MAXnewcentrum) {
       facet2->keepcentrum= True;
       zinc_(Zwidevertices);
     }
   }else if (size <= qh->hull_dim + qh_MAXnewcentrum) {
     /* center and keepcentrum was set */
     if (size == qh->hull_dim || qh->POSTmerging)
       facet2->keepcentrum= False; /* if many merges need to recompute centrum */
   }
   if (!facet2->keepcentrum) {
     qh_memfree(qh, facet2->center, qh->normal_size);
     facet2->center= NULL;
     FOREACHridge_(facet2->ridges)
       ridge->tested= False;
   }
 } /* updatetested */
 
 /*---------------------------------
 
   qh_vertexridges(qh, vertex )
     return temporary set of ridges adjacent to a vertex
     vertex->neighbors defined
 
   ntoes:
     uses qh.visit_id
     does not include implicit ridges for simplicial facets
 
   design:
     for each neighbor of vertex
       add ridges that include the vertex to ridges
 */
 setT *qh_vertexridges(qhT *qh, vertexT *vertex) {
   facetT *neighbor, **neighborp;
   setT *ridges= qh_settemp(qh, qh->TEMPsize);
   int size;
 
   qh->visit_id++;
   FOREACHneighbor_(vertex)
     neighbor->visitid= qh->visit_id;
   FOREACHneighbor_(vertex) {
     if (*neighborp)   /* no new ridges in last neighbor */
       qh_vertexridges_facet(qh, vertex, neighbor, &ridges);
   }
   if (qh->PRINTstatistics || qh->IStracing) {
     size= qh_setsize(qh, ridges);
     zinc_(Zvertexridge);
     zadd_(Zvertexridgetot, size);
     zmax_(Zvertexridgemax, size);
     trace3((qh, qh->ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",
              size, vertex->id));
   }
   return ridges;
 } /* vertexridges */
 
 /*---------------------------------
 
   qh_vertexridges_facet(qh, vertex, facet, ridges )
     add adjacent ridges for vertex in facet
     neighbor->visitid==qh.visit_id if it hasn't been visited
 
   returns:
     ridges updated
     sets facet->visitid to qh.visit_id-1
 
   design:
     for each ridge of facet
       if ridge of visited neighbor (i.e., unprocessed)
         if vertex in ridge
           append ridge to vertex
     mark facet processed
 */
 void qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges) {
   ridgeT *ridge, **ridgep;
   facetT *neighbor;
 
   FOREACHridge_(facet->ridges) {
     neighbor= otherfacet_(ridge, facet);
     if (neighbor->visitid == qh->visit_id
     && qh_setin(ridge->vertices, vertex))
       qh_setappend(qh, ridges, ridge);
   }
   facet->visitid= qh->visit_id-1;
 } /* vertexridges_facet */
 
 /*---------------------------------
 
   qh_willdelete(qh, facet, replace )
     moves facet to visible list
     sets facet->f.replace to replace (may be NULL)
 
   returns:
     bumps qh.num_visible
 */
 void qh_willdelete(qhT *qh, facetT *facet, facetT *replace) {
 
   qh_removefacet(qh, facet);
   qh_prependfacet(qh, facet, &qh->visible_list);
   qh->num_visible++;
   facet->visible= True;
   facet->f.replace= replace;
 } /* willdelete */
 
 #else /* qh_NOmerge */
 void qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle) {
 }
 void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
                       boolT vneighbors) {
 }
 boolT qh_checkzero(qhT *qh, boolT testall) {
    }
 #endif /* qh_NOmerge */
 
diff --git a/src/libqhullr/merge_r.h b/src/libqhullr/merge_r.h
index 807e0b2..4d71d34 100644
--- a/src/libqhullr/merge_r.h
+++ b/src/libqhullr/merge_r.h
@@ -1,178 +1,178 @@
 /*
  ---------------------------------
 
    merge_r.h
    header file for merge_r.c
 
    see qh-merge.htm and merge_r.c
 
-   Copyright (c) 1993-2014 C.B. Barber.
-   $Id: //main/2011/qhull/src/libqhullr/merge_r.h#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 C.B. Barber.
+   $Id: //main/2011/qhull/src/libqhullr/merge_r.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFmerge
 #define qhDEFmerge 1
 
 #include "libqhull_r.h"
 
 
 /*============ -constants- ==============*/
 
 /*----------------------------------
 
   qh_ANGLEredundant
     indicates redundant merge in mergeT->angle
 */
 #define qh_ANGLEredundant 6.0
 
 /*----------------------------------
 
   qh_ANGLEdegen
     indicates degenerate facet in mergeT->angle
 */
 #define qh_ANGLEdegen     5.0
 
 /*----------------------------------
 
   qh_ANGLEconcave
     offset to indicate concave facets in mergeT->angle
 
   notes:
     concave facets are assigned the range of [2,4] in mergeT->angle
     roundoff error may make the angle less than 2
 */
 #define qh_ANGLEconcave  1.5
 
 /*----------------------------------
 
   MRG... (mergeType)
     indicates the type of a merge (mergeT->type)
 */
 typedef enum {  /* in sort order for facet_mergeset */
   MRGnone= 0,
   MRGcoplanar,          /* centrum coplanar */
   MRGanglecoplanar,     /* angle coplanar */
                         /* could detect half concave ridges */
   MRGconcave,           /* concave ridge */
   MRGflip,              /* flipped facet. facet1 == facet2 */
   MRGridge,             /* duplicate ridge (qh_MERGEridge) */
                         /* degen and redundant go onto degen_mergeset */
   MRGdegen,             /* degenerate facet (!enough neighbors) facet1 == facet2 */
   MRGredundant,         /* redundant facet (vertex subset) */
                         /* merge_degenredundant assumes degen < redundant */
   MRGmirror,            /* mirror facet from qh_triangulate */
   ENDmrg
 } mergeType;
 
 /*----------------------------------
 
   qh_MERGEapex
     flag for qh_mergefacet() to indicate an apex merge
 */
 #define qh_MERGEapex     True
 
 /*============ -structures- ====================*/
 
 /*----------------------------------
 
   mergeT
     structure used to merge facets
 */
 
 typedef struct mergeT mergeT;
 struct mergeT {         /* initialize in qh_appendmergeset */
   realT   angle;        /* angle between normals of facet1 and facet2 */
   facetT *facet1;       /* will merge facet1 into facet2 */
   facetT *facet2;
   mergeType type;
 };
 
 
 /*=========== -macros- =========================*/
 
 /*----------------------------------
 
   FOREACHmerge_( merges ) {...}
     assign 'merge' to each merge in merges
 
   notes:
     uses 'mergeT *merge, **mergep;'
     if qh_mergefacet(),
       restart since qh.facet_mergeset may change
     see FOREACHsetelement_
 */
 #define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
 
 /*============ prototypes in alphabetical order after pre/postmerge =======*/
 
 void    qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle);
 void    qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
              boolT vneighbors);
 void    qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors);
 void    qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
 setT   *qh_basevertices(qhT *qh, facetT *samecycle);
 void    qh_checkconnect(qhT *qh /* qh.new_facets */);
 boolT   qh_checkzero(qhT *qh, boolT testall);
 int     qh_compareangle(const void *p1, const void *p2);
 int     qh_comparemerge(const void *p1, const void *p2);
 int     qh_comparevisit(const void *p1, const void *p2);
 void    qh_copynonconvex(qhT *qh, ridgeT *atridge);
 void    qh_degen_redundant_facet(qhT *qh, facetT *facet);
 void    qh_degen_redundant_neighbors(qhT *qh, facetT *facet, facetT *delfacet);
 vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges);
 void    qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
            facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
 facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
 void    qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge);
 void    qh_forcedmerges(qhT *qh, boolT *wasmerge);
 void    qh_getmergeset(qhT *qh, facetT *facetlist);
 void    qh_getmergeset_initial(qhT *qh, facetT *facetlist);
 void    qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
 ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
               vertexT *vertex, vertexT *oldvertex, int *hashslot);
 void    qh_makeridges(qhT *qh, facetT *facet);
 void    qh_mark_dupridges(qhT *qh, facetT *facetlist);
 void    qh_maydropneighbor(qhT *qh, facetT *facet);
 int     qh_merge_degenredundant(qhT *qh);
 void    qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype);
 void    qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge);
 void    qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet);
 void    qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet);
 void    qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
 void    qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2);
 void    qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2);
 void    qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2);
 void    qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex);
 void    qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2);
 void    qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2);
 void    qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices);
 setT   *qh_neighbor_intersections(qhT *qh, vertexT *vertex);
 void    qh_newvertices(qhT *qh, setT *vertices);
 boolT   qh_reducevertices(qhT *qh);
 vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex);
 boolT   qh_remove_extravertices(qhT *qh, facetT *facet);
 vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet);
 void    qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
 void    qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges,
                         facetT *oldfacet, facetT *neighborA);
 boolT   qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor);
 boolT   qh_test_vneighbors(qhT *qh /* qh.newfacet_list */);
 void    qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2);
 void    qh_tracemerging(qhT *qh);
 void    qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2);
 setT   *qh_vertexridges(qhT *qh, vertexT *vertex);
 void    qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges);
 void    qh_willdelete(qhT *qh, facetT *facet, facetT *replace);
 
 #endif /* qhDEFmerge */
diff --git a/src/libqhullr/poly2_r.c b/src/libqhullr/poly2_r.c
index b312a5c..1e99af7 100644
--- a/src/libqhullr/poly2_r.c
+++ b/src/libqhullr/poly2_r.c
@@ -1,3153 +1,3153 @@
 /*
  ---------------------------------
 
    poly2_r.c
    implements polygons and simplicies
 
    see qh-poly.htm, poly_r.h and libqhull_r.h
 
    frequently used code is in poly_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/poly2_r.c#7 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/poly2_r.c#8 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_ra.h"
 
 /*======== functions in alphabetical order ==========*/
 
 /*---------------------------------
 
   qh_addhash(qh, newelem, hashtable, hashsize, hash )
     add newelem to linear hash table at hash if not already there
 */
 void qh_addhash(qhT *qh, void *newelem, setT *hashtable, int hashsize, int hash) {
   int scan;
   void *elem;
 
   for (scan= (int)hash; (elem= SETelem_(hashtable, scan));
        scan= (++scan >= hashsize ? 0 : scan)) {
     if (elem == newelem)
       break;
   }
   /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
   if (!elem)
     SETelem_(hashtable, scan)= newelem;
 } /* addhash */
 
 /*---------------------------------
 
   qh_check_bestdist(qh)
     check that all points are within max_outside of the nearest facet
     if qh.ONLYgood,
       ignores !good facets
 
   see:
     qh_check_maxout(), qh_outerinner()
 
   notes:
     only called from qh_check_points()
       seldom used since qh.MERGING is almost always set
     if notverified>0 at end of routine
       some points were well inside the hull.  If the hull contains
       a lens-shaped component, these points were not verified.  Use
       options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
 
   design:
     determine facet for each point (if any)
     for each point
       start with the assigned facet or with the first facet
       find the best facet for the point and check all coplanar facets
       error if point is outside of facet
 */
 void qh_check_bestdist(qhT *qh) {
   boolT waserror= False, unassigned;
   facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
   facetT *facetlist;
   realT dist, maxoutside, maxdist= -REALmax;
   pointT *point;
   int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
   setT *facets;
 
   trace1((qh, qh->ferr, 1020, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
       qh->facet_list->id));
   maxoutside= qh_maxouter(qh);
   maxoutside += qh->DISTround;
   /* one more qh.DISTround for check computation */
   trace1((qh, qh->ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
   facets= qh_pointfacet(qh /*qh.facet_list*/);
   if (!qh_QUICKhelp && qh->PRINTprecision)
     qh_fprintf(qh, qh->ferr, 8091, "\n\
 qhull output completed.  Verifying that %d points are\n\
 below %2.2g of the nearest %sfacet.\n",
              qh_setsize(qh, facets), maxoutside, (qh->ONLYgood ?  "good " : ""));
   FOREACHfacet_i_(qh, facets) {  /* for each point with facet assignment */
     if (facet)
       unassigned= False;
     else {
       unassigned= True;
       facet= qh->facet_list;
     }
     point= qh_point(qh, facet_i);
     if (point == qh->GOODpointp)
       continue;
     qh_distplane(qh, point, facet, &dist);
     numpart++;
     bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
     /* occurs after statistics reported */
     maximize_(maxdist, dist);
     if (dist > maxoutside) {
       if (qh->ONLYgood && !bestfacet->good
           && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
                && dist > maxoutside))
         notgood++;
       else {
         waserror= True;
         qh_fprintf(qh, qh->ferr, 6109, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
                 facet_i, bestfacet->id, dist, maxoutside);
         if (errfacet1 != bestfacet) {
           errfacet2= errfacet1;
           errfacet1= bestfacet;
         }
       }
     }else if (unassigned && dist < -qh->MAXcoplanar)
       notverified++;
   }
   qh_settempfree(qh, &facets);
   if (notverified && !qh->DELAUNAY && !qh_QUICKhelp && qh->PRINTprecision)
     qh_fprintf(qh, qh->ferr, 8092, "\n%d points were well inside the hull.  If the hull contains\n\
 a lens-shaped component, these points were not verified.  Use\n\
 options 'Qci Tv' to verify all points.\n", notverified);
   if (maxdist > qh->outside_err) {
     qh_fprintf(qh, qh->ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
               maxdist, qh->outside_err);
     qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
   }else if (waserror && qh->outside_err > REALmax/2)
     qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
   /* else if waserror, the error was logged to qh.ferr but does not effect the output */
   trace0((qh, qh->ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
 } /* check_bestdist */
 
 /*---------------------------------
 
   qh_check_maxout(qh)
     updates qh.max_outside by checking all points against bestfacet
     if qh.ONLYgood, ignores !good facets
 
   returns:
     updates facet->maxoutside via qh_findbesthorizon()
     sets qh.maxoutdone
     if printing qh.min_vertex (qh_outerinner),
       it is updated to the current vertices
     removes inside/coplanar points from coplanarset as needed
 
   notes:
     defines coplanar as min_vertex instead of MAXcoplanar
     may not need to check near-inside points because of qh.MAXcoplanar
       and qh.KEEPnearinside (before it was -DISTround)
 
   see also:
     qh_check_bestdist()
 
   design:
     if qh.min_vertex is needed
       for all neighbors of all vertices
         test distance from vertex to neighbor
     determine facet for each point (if any)
     for each point with an assigned facet
       find the best facet for the point and check all coplanar facets
         (updates outer planes)
     remove near-inside points from coplanar sets
 */
 #ifndef qh_NOmerge
 void qh_check_maxout(qhT *qh) {
   facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;
   realT dist, maxoutside, minvertex, old_maxoutside;
   pointT *point;
   int numpart= 0, facet_i, facet_n, notgood= 0;
   setT *facets, *vertices;
   vertexT *vertex;
 
   trace1((qh, qh->ferr, 1022, "qh_check_maxout: check and update maxoutside for each facet.\n"));
   maxoutside= minvertex= 0;
   if (qh->VERTEXneighbors
   && (qh->PRINTsummary || qh->KEEPinside || qh->KEEPcoplanar
         || qh->TRACElevel || qh->PRINTstatistics
         || qh->PRINTout[0] == qh_PRINTsummary || qh->PRINTout[0] == qh_PRINTnone)) {
     trace1((qh, qh->ferr, 1023, "qh_check_maxout: determine actual maxoutside and minvertex\n"));
     vertices= qh_pointvertex(qh /*qh.facet_list*/);
     FORALLvertices {
       FOREACHneighbor_(vertex) {
         zinc_(Zdistvertex);  /* distance also computed by main loop below */
         qh_distplane(qh, vertex->point, neighbor, &dist);
         minimize_(minvertex, dist);
         if (-dist > qh->TRACEdist || dist > qh->TRACEdist
         || neighbor == qh->tracefacet || vertex == qh->tracevertex)
           qh_fprintf(qh, qh->ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d\n",
                     qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
       }
     }
     if (qh->MERGING) {
       wmin_(Wminvertex, qh->min_vertex);
     }
     qh->min_vertex= minvertex;
     qh_settempfree(qh, &vertices);
   }
   facets= qh_pointfacet(qh /*qh.facet_list*/);
   do {
     old_maxoutside= fmax_(qh->max_outside, maxoutside);
     FOREACHfacet_i_(qh, facets) {     /* for each point with facet assignment */
       if (facet) {
         point= qh_point(qh, facet_i);
         if (point == qh->GOODpointp)
           continue;
         zzinc_(Ztotcheck);
         qh_distplane(qh, point, facet, &dist);
         numpart++;
         bestfacet= qh_findbesthorizon(qh, qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
         if (bestfacet && dist > maxoutside) {
           if (qh->ONLYgood && !bestfacet->good
           && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
                && dist > maxoutside))
             notgood++;
           else
             maxoutside= dist;
         }
         if (dist > qh->TRACEdist || (bestfacet && bestfacet == qh->tracefacet))
           qh_fprintf(qh, qh->ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",
                      qh_pointid(qh, point), dist, bestfacet->id);
       }
     }
   }while
     (maxoutside > 2*old_maxoutside);
     /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid
           e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */
   zzadd_(Zcheckpart, numpart);
   qh_settempfree(qh, &facets);
   wval_(Wmaxout)= maxoutside - qh->max_outside;
   wmax_(Wmaxoutside, qh->max_outside);
   qh->max_outside= maxoutside;
   qh_nearcoplanar(qh /*qh.facet_list*/);
   qh->maxoutdone= True;
   trace1((qh, qh->ferr, 1024, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",
        maxoutside, qh->min_vertex, notgood));
 } /* check_maxout */
 #else /* qh_NOmerge */
 void qh_check_maxout(qhT *qh) {
 }
 #endif
 
 /*---------------------------------
 
   qh_check_output(qh)
     performs the checks at the end of qhull algorithm
     Maybe called after voronoi output.  Will recompute otherwise centrums are Voronoi centers instead
 */
 void qh_check_output(qhT *qh) {
   int i;
 
   if (qh->STOPcone)
     return;
   if (qh->VERIFYoutput | qh->IStracing | qh->CHECKfrequently) {
     qh_checkpolygon(qh, qh->facet_list);
     qh_checkflipped_all(qh, qh->facet_list);
     qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
   }else if (!qh->MERGING && qh_newstats(qh, qh->qhstat.precision, &i)) {
     qh_checkflipped_all(qh, qh->facet_list);
     qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
   }
 } /* check_output */
 
 
 
 /*---------------------------------
 
   qh_check_point(qh, point, facet, maxoutside, maxdist, errfacet1, errfacet2 )
     check that point is less than maxoutside from facet
 */
 void qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {
   realT dist;
 
   /* occurs after statistics reported */
   qh_distplane(qh, point, facet, &dist);
   if (dist > *maxoutside) {
     if (*errfacet1 != facet) {
       *errfacet2= *errfacet1;
       *errfacet1= facet;
     }
     qh_fprintf(qh, qh->ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
               qh_pointid(qh, point), facet->id, dist, *maxoutside);
   }
   maximize_(*maxdist, dist);
 } /* qh_check_point */
 
 
 /*---------------------------------
 
   qh_check_points(qh)
     checks that all points are inside all facets
 
   notes:
     if many points and qh_check_maxout not called (i.e., !qh.MERGING),
        calls qh_findbesthorizon (seldom done).
     ignores flipped facets
     maxoutside includes 2 qh.DISTrounds
       one qh.DISTround for the computed distances in qh_check_points
     qh_printafacet and qh_printsummary needs only one qh.DISTround
     the computation for qh.VERIFYdirect does not account for qh.other_points
 
   design:
     if many points
       use qh_check_bestdist()
     else
       for all facets
         for all points
           check that point is inside facet
 */
 void qh_check_points(qhT *qh) {
   facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
   realT total, maxoutside, maxdist= -REALmax;
   pointT *point, **pointp, *pointtemp;
   boolT testouter;
 
   maxoutside= qh_maxouter(qh);
   maxoutside += qh->DISTround;
   /* one more qh.DISTround for check computation */
   trace1((qh, qh->ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",
           maxoutside));
   if (qh->num_good)   /* miss counts other_points and !good facets */
      total= (float)qh->num_good * (float)qh->num_points;
   else
      total= (float)qh->num_facets * (float)qh->num_points;
   if (total >= qh_VERIFYdirect && !qh->maxoutdone) {
     if (!qh_QUICKhelp && qh->SKIPcheckmax && qh->MERGING)
       qh_fprintf(qh, qh->ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').\n\
 Verify may report that a point is outside of a facet.\n");
     qh_check_bestdist(qh);
   }else {
     if (qh_MAXoutside && qh->maxoutdone)
       testouter= True;
     else
       testouter= False;
     if (!qh_QUICKhelp) {
       if (qh->MERGEexact)
         qh_fprintf(qh, qh->ferr, 7076, "qhull input warning: exact merge ('Qx').  Verify may report that a point\n\
 is outside of a facet.  See qh-optq.htm#Qx\n");
       else if (qh->SKIPcheckmax || qh->NOnearinside)
         qh_fprintf(qh, qh->ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of\n\
 near-inside points ('Q8').  Verify may report that a point is outside\n\
 of a facet.\n");
     }
     if (qh->PRINTprecision) {
       if (testouter)
         qh_fprintf(qh, qh->ferr, 8098, "\n\
 Output completed.  Verifying that all points are below outer planes of\n\
 all %sfacets.  Will make %2.0f distance computations.\n",
               (qh->ONLYgood ?  "good " : ""), total);
       else
         qh_fprintf(qh, qh->ferr, 8099, "\n\
 Output completed.  Verifying that all points are below %2.2g of\n\
 all %sfacets.  Will make %2.0f distance computations.\n",
               maxoutside, (qh->ONLYgood ?  "good " : ""), total);
     }
     FORALLfacets {
       if (!facet->good && qh->ONLYgood)
         continue;
       if (facet->flipped)
         continue;
       if (!facet->normal) {
         qh_fprintf(qh, qh->ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
         continue;
       }
       if (testouter) {
 #if qh_MAXoutside
         maxoutside= facet->maxoutside + 2* qh->DISTround;
         /* one DISTround to actual point and another to computed point */
 #endif
       }
       FORALLpoints {
         if (point != qh->GOODpointp)
           qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
       }
       FOREACHpoint_(qh->other_points) {
         if (point != qh->GOODpointp)
           qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
       }
     }
     if (maxdist > qh->outside_err) {
       qh_fprintf(qh, qh->ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
                 maxdist, qh->outside_err );
       qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
     }else if (errfacet1 && qh->outside_err > REALmax/2)
         qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
     /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */
     trace0((qh, qh->ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));
   }
 } /* check_points */
 
 
 /*---------------------------------
 
   qh_checkconvex(qh, facetlist, fault )
     check that each ridge in facetlist is convex
     fault = qh_DATAfault if reporting errors
           = qh_ALGORITHMfault otherwise
 
   returns:
     counts Zconcaveridges and Zcoplanarridges
     errors if concaveridge or if merging an coplanar ridge
 
   note:
     if not merging,
       tests vertices for neighboring simplicial facets
     else if ZEROcentrum,
       tests vertices for neighboring simplicial   facets
     else
       tests centrums of neighboring facets
 
   design:
     for all facets
       report flipped facets
       if ZEROcentrum and simplicial neighbors
         test vertices for neighboring simplicial facets
       else
         test centrum against all neighbors
 */
 void qh_checkconvex(qhT *qh, facetT *facetlist, int fault) {
   facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
   vertexT *vertex;
   realT dist;
   pointT *centrum;
   boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;
   int neighbor_i;
 
   trace1((qh, qh->ferr, 1026, "qh_checkconvex: check all ridges are convex\n"));
   if (!qh->RERUN) {
     zzval_(Zconcaveridges)= 0;
     zzval_(Zcoplanarridges)= 0;
   }
   FORALLfacet_(facetlist) {
     if (facet->flipped) {
       qh_precision(qh, "flipped facet");
       qh_fprintf(qh, qh->ferr, 6113, "qhull precision error: f%d is flipped(interior point is outside)\n",
                facet->id);
       errfacet1= facet;
       waserror= True;
       continue;
     }
     if (qh->MERGING && (!qh->ZEROcentrum || !facet->simplicial || facet->tricoplanar))
       allsimplicial= False;
     else {
       allsimplicial= True;
       neighbor_i= 0;
       FOREACHneighbor_(facet) {
         vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
         if (!neighbor->simplicial || neighbor->tricoplanar) {
           allsimplicial= False;
           continue;
         }
         qh_distplane(qh, vertex->point, neighbor, &dist);
         if (dist > -qh->DISTround) {
           if (fault == qh_DATAfault) {
             qh_precision(qh, "coplanar or concave ridge");
             qh_fprintf(qh, qh->ferr, 6114, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);
             qh_errexit(qh, qh_ERRsingular, NULL, NULL);
           }
           if (dist > qh->DISTround) {
             zzinc_(Zconcaveridges);
             qh_precision(qh, "concave ridge");
             qh_fprintf(qh, qh->ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above\n",
               facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist);
             errfacet1= facet;
             errfacet2= neighbor;
             waserror= True;
           }else if (qh->ZEROcentrum) {
             if (dist > 0) {     /* qh_checkzero checks that dist < - qh->DISTround */
               zzinc_(Zcoplanarridges);
               qh_precision(qh, "coplanar ridge");
               qh_fprintf(qh, qh->ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above\n",
                 facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist);
               errfacet1= facet;
               errfacet2= neighbor;
               waserror= True;
             }
           }else {
             zzinc_(Zcoplanarridges);
             qh_precision(qh, "coplanar ridge");
             trace0((qh, qh->ferr, 22, "qhull precision error: f%d may be coplanar to f%d, since p%d(v%d) is within %6.4g during p%d\n",
               facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, qh->furthest_id));
           }
         }
       }
     }
     if (!allsimplicial) {
       if (qh->CENTERtype == qh_AScentrum) {
         if (!facet->center)
           facet->center= qh_getcentrum(qh, facet);
         centrum= facet->center;
       }else {
         if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {
            centrum_warning= True;
            qh_fprintf(qh, qh->ferr, 7062, "qhull warning: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
         }
         centrum= qh_getcentrum(qh, facet);
         tempcentrum= True;
       }
       FOREACHneighbor_(facet) {
         if (qh->ZEROcentrum && facet->simplicial && neighbor->simplicial)
           continue;
         if (facet->tricoplanar || neighbor->tricoplanar)
           continue;
         zzinc_(Zdistconvex);
         qh_distplane(qh, centrum, neighbor, &dist);
         if (dist > qh->DISTround) {
           zzinc_(Zconcaveridges);
           qh_precision(qh, "concave ridge");
           qh_fprintf(qh, qh->ferr, 6117, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
             facet->id, neighbor->id, facet->id, dist, neighbor->id);
           errfacet1= facet;
           errfacet2= neighbor;
           waserror= True;
         }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
                                      can test against centrum radius instead */
           zzinc_(Zcoplanarridges);
           qh_precision(qh, "coplanar ridge");
           qh_fprintf(qh, qh->ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
             facet->id, neighbor->id, facet->id, dist, neighbor->id);
           errfacet1= facet;
           errfacet2= neighbor;
           waserror= True;
         }
       }
       if (tempcentrum)
         qh_memfree(qh, centrum, qh->normal_size);
     }
   }
   if (waserror && !qh->FORCEoutput)
     qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
 } /* checkconvex */
 
 
 /*---------------------------------
 
   qh_checkfacet(qh, facet, newmerge, waserror )
     checks for consistency errors in facet
     newmerge set if from merge_r.c
 
   returns:
     sets waserror if any error occurs
 
   checks:
     vertex ids are inverse sorted
     unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
     if non-simplicial, at least as many ridges as neighbors
     neighbors are not duplicated
     ridges are not duplicated
     in 3-d, ridges=verticies
     (qh.hull_dim-1) ridge vertices
     neighbors are reciprocated
     ridge neighbors are facet neighbors and a ridge for every neighbor
     simplicial neighbors match facetintersect
     vertex intersection matches vertices of common ridges
     vertex neighbors and facet vertices agree
     all ridges have distinct vertex sets
 
   notes:
     uses neighbor->seen
 
   design:
     check sets
     check vertices
     check sizes of neighbors and vertices
     check for qh_MERGEridge and qh_DUPLICATEridge flags
     check neighbor set
     check ridge set
     check ridges, neighbors, and vertices
 */
 void qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp) {
   facetT *neighbor, **neighborp, *errother=NULL;
   ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
   vertexT *vertex, **vertexp;
   unsigned previousid= INT_MAX;
   int numneighbors, numvertices, numridges=0, numRvertices=0;
   boolT waserror= False;
   int skipA, skipB, ridge_i, ridge_n, i;
   setT *intersection;
 
   if (facet->visible) {
     qh_fprintf(qh, qh->ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",
       facet->id);
     qh_errexit(qh, qh_ERRqhull, facet, NULL);
   }
   if (!facet->normal) {
     qh_fprintf(qh, qh->ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have  a normal\n",
       facet->id);
     waserror= True;
   }
   qh_setcheck(qh, facet->vertices, "vertices for f", facet->id);
   qh_setcheck(qh, facet->ridges, "ridges for f", facet->id);
   qh_setcheck(qh, facet->outsideset, "outsideset for f", facet->id);
   qh_setcheck(qh, facet->coplanarset, "coplanarset for f", facet->id);
   qh_setcheck(qh, facet->neighbors, "neighbors for f", facet->id);
   FOREACHvertex_(facet->vertices) {
     if (vertex->deleted) {
       qh_fprintf(qh, qh->ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
       qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
       waserror= True;
     }
     if (vertex->id >= previousid) {
       qh_fprintf(qh, qh->ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
       waserror= True;
       break;
     }
     previousid= vertex->id;
   }
   numneighbors= qh_setsize(qh, facet->neighbors);
   numvertices= qh_setsize(qh, facet->vertices);
   numridges= qh_setsize(qh, facet->ridges);
   if (facet->simplicial) {
     if (numvertices+numneighbors != 2*qh->hull_dim
     && !facet->degenerate && !facet->redundant) {
       qh_fprintf(qh, qh->ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh->hull_dim\n",
                 facet->id, numvertices, numneighbors);
       qh_setprint(qh, qh->ferr, "", facet->neighbors);
       waserror= True;
     }
   }else { /* non-simplicial */
     if (!newmerge
     &&(numvertices < qh->hull_dim || numneighbors < qh->hull_dim)
     && !facet->degenerate && !facet->redundant) {
       qh_fprintf(qh, qh->ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh->hull_dim\n",
          facet->id, numvertices, numneighbors);
        waserror= True;
     }
     /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
     if (numridges < numneighbors
     ||(qh->hull_dim == 3 && numvertices > numridges && !qh->NEWfacets)
     ||(qh->hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
       if (!facet->degenerate && !facet->redundant) {
         qh_fprintf(qh, qh->ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",
             facet->id, numridges, numneighbors, numvertices);
         waserror= True;
       }
     }
   }
   FOREACHneighbor_(facet) {
     if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
       qh_fprintf(qh, qh->ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);
       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     }
     neighbor->seen= True;
   }
   FOREACHneighbor_(facet) {
     if (!qh_setin(neighbor->neighbors, facet)) {
       qh_fprintf(qh, qh->ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
               facet->id, neighbor->id, neighbor->id, facet->id);
       errother= neighbor;
       waserror= True;
     }
     if (!neighbor->seen) {
       qh_fprintf(qh, qh->ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
               facet->id, neighbor->id);
       errother= neighbor;
       waserror= True;
     }
     neighbor->seen= False;
   }
   FOREACHridge_(facet->ridges) {
     qh_setcheck(qh, ridge->vertices, "vertices for r", ridge->id);
     ridge->seen= False;
   }
   FOREACHridge_(facet->ridges) {
     if (ridge->seen) {
       qh_fprintf(qh, qh->ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
               facet->id, ridge->id);
       errridge= ridge;
       waserror= True;
     }
     ridge->seen= True;
     numRvertices= qh_setsize(qh, ridge->vertices);
     if (numRvertices != qh->hull_dim - 1) {
       qh_fprintf(qh, qh->ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",
                 ridge->top->id, ridge->bottom->id, numRvertices);
       errridge= ridge;
       waserror= True;
     }
     neighbor= otherfacet_(ridge, facet);
     neighbor->seen= True;
     if (!qh_setin(facet->neighbors, neighbor)) {
       qh_fprintf(qh, qh->ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
            facet->id, neighbor->id, ridge->id);
       errridge= ridge;
       waserror= True;
     }
   }
   if (!facet->simplicial) {
     FOREACHneighbor_(facet) {
       if (!neighbor->seen) {
         qh_fprintf(qh, qh->ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
               facet->id, neighbor->id);
         errother= neighbor;
         waserror= True;
       }
       intersection= qh_vertexintersect_new(qh, facet->vertices, neighbor->vertices);
       qh_settemppush(qh, intersection);
       FOREACHvertex_(facet->vertices) {
         vertex->seen= False;
         vertex->seen2= False;
       }
       FOREACHvertex_(intersection)
         vertex->seen= True;
       FOREACHridge_(facet->ridges) {
         if (neighbor != otherfacet_(ridge, facet))
             continue;
         FOREACHvertex_(ridge->vertices) {
           if (!vertex->seen) {
             qh_fprintf(qh, qh->ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
                   vertex->id, ridge->id, facet->id, neighbor->id);
             qh_errexit(qh, qh_ERRqhull, facet, ridge);
           }
           vertex->seen2= True;
         }
       }
       if (!newmerge) {
         FOREACHvertex_(intersection) {
           if (!vertex->seen2) {
             if (qh->IStracing >=3 || !qh->MERGING) {
               qh_fprintf(qh, qh->ferr, 6134, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\
  not in a ridge.  This is ok under merging.  Last point was p%d\n",
                      vertex->id, facet->id, neighbor->id, qh->furthest_id);
               if (!qh->FORCEoutput && !qh->MERGING) {
                 qh_errprint(qh, "ERRONEOUS", facet, neighbor, NULL, vertex);
                 if (!qh->MERGING)
                   qh_errexit(qh, qh_ERRqhull, NULL, NULL);
               }
             }
           }
         }
       }
       qh_settempfree(qh, &intersection);
     }
   }else { /* simplicial */
     FOREACHneighbor_(facet) {
       if (neighbor->simplicial) {
         skipA= SETindex_(facet->neighbors, neighbor);
         skipB= qh_setindex(neighbor->neighbors, facet);
         if (!qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {
           qh_fprintf(qh, qh->ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
                    facet->id, skipA, neighbor->id, skipB);
           errother= neighbor;
           waserror= True;
         }
       }
     }
   }
   if (qh->hull_dim < 5 && (qh->IStracing > 2 || qh->CHECKfrequently)) {
     FOREACHridge_i_(qh, facet->ridges) {           /* expensive */
       for (i=ridge_i+1; i < ridge_n; i++) {
         ridge2= SETelemt_(facet->ridges, i, ridgeT);
         if (qh_setequal(ridge->vertices, ridge2->vertices)) {
           qh_fprintf(qh, qh->ferr, 6227, "Qhull internal error (qh_checkfacet): ridges r%d and r%d have the same vertices\n",
                   ridge->id, ridge2->id);
           errridge= ridge;
           waserror= True;
         }
       }
     }
   }
   if (waserror) {
     qh_errprint(qh, "ERRONEOUS", facet, errother, errridge, NULL);
     *waserrorp= True;
   }
 } /* checkfacet */
 
 
 /*---------------------------------
 
   qh_checkflipped_all(qh, facetlist )
     checks orientation of facets in list against interior point
 */
 void qh_checkflipped_all(qhT *qh, facetT *facetlist) {
   facetT *facet;
   boolT waserror= False;
   realT dist;
 
   if (facetlist == qh->facet_list)
     zzval_(Zflippedfacets)= 0;
   FORALLfacet_(facetlist) {
     if (facet->normal && !qh_checkflipped(qh, facet, &dist, !qh_ALL)) {
       qh_fprintf(qh, qh->ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
               facet->id, dist);
       if (!qh->FORCEoutput) {
         qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, NULL);
         waserror= True;
       }
     }
   }
   if (waserror) {
     qh_fprintf(qh, qh->ferr, 8101, "\n\
 A flipped facet occurs when its distance to the interior point is\n\
 greater than %2.2g, the maximum roundoff error.\n", -qh->DISTround);
     qh_errexit(qh, qh_ERRprec, NULL, NULL);
   }
 } /* checkflipped_all */
 
 /*---------------------------------
 
   qh_checkpolygon(qh, facetlist )
     checks the correctness of the structure
 
   notes:
     call with either qh.facet_list or qh.newfacet_list
     checks num_facets and num_vertices if qh.facet_list
 
   design:
     for each facet
       checks facet and outside set
     initializes vertexlist
     for each facet
       checks vertex set
     if checking all facets(qh.facetlist)
       check facet count
       if qh.VERTEXneighbors
         check vertex neighbors and count
       check vertex count
 */
 void qh_checkpolygon(qhT *qh, facetT *facetlist) {
   facetT *facet;
   vertexT *vertex, **vertexp, *vertexlist;
   int numfacets= 0, numvertices= 0, numridges= 0;
   int totvneighbors= 0, totvertices= 0;
   boolT waserror= False, nextseen= False, visibleseen= False;
 
   trace1((qh, qh->ferr, 1027, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));
   if (facetlist != qh->facet_list || qh->ONLYgood)
     nextseen= True;
   FORALLfacet_(facetlist) {
     if (facet == qh->visible_list)
       visibleseen= True;
     if (!facet->visible) {
       if (!nextseen) {
         if (facet == qh->facet_next)
           nextseen= True;
         else if (qh_setsize(qh, facet->outsideset)) {
           if (!qh->NARROWhull
 #if !qh_COMPUTEfurthest
                || facet->furthestdist >= qh->MINoutside
 #endif
                         ) {
             qh_fprintf(qh, qh->ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh->facet_next\n",
                      facet->id);
             qh_errexit(qh, qh_ERRqhull, facet, NULL);
           }
         }
       }
       numfacets++;
       qh_checkfacet(qh, facet, False, &waserror);
     }
   }
   if (qh->visible_list && !visibleseen && facetlist == qh->facet_list) {
     qh_fprintf(qh, qh->ferr, 6138, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh->visible_list->id);
     qh_printlists(qh);
     qh_errexit(qh, qh_ERRqhull, qh->visible_list, NULL);
   }
   if (facetlist == qh->facet_list)
     vertexlist= qh->vertex_list;
   else if (facetlist == qh->newfacet_list)
     vertexlist= qh->newvertex_list;
   else
     vertexlist= NULL;
   FORALLvertex_(vertexlist) {
     vertex->seen= False;
     vertex->visitid= 0;
   }
   FORALLfacet_(facetlist) {
     if (facet->visible)
       continue;
     if (facet->simplicial)
       numridges += qh->hull_dim;
     else
       numridges += qh_setsize(qh, facet->ridges);
     FOREACHvertex_(facet->vertices) {
       vertex->visitid++;
       if (!vertex->seen) {
         vertex->seen= True;
         numvertices++;
         if (qh_pointid(qh, vertex->point) == -1) {
           qh_fprintf(qh, qh->ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
                    vertex->point, vertex->id, qh->first_point);
           waserror= True;
         }
       }
     }
   }
   qh->vertex_visit += (unsigned int)numfacets;
   if (facetlist == qh->facet_list) {
     if (numfacets != qh->num_facets - qh->num_visible) {
       qh_fprintf(qh, qh->ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
               numfacets, qh->num_facets, qh->num_visible);
       waserror= True;
     }
     qh->vertex_visit++;
     if (qh->VERTEXneighbors) {
       FORALLvertices {
         qh_setcheck(qh, vertex->neighbors, "neighbors for v", vertex->id);
         if (vertex->deleted)
           continue;
         totvneighbors += qh_setsize(qh, vertex->neighbors);
       }
       FORALLfacet_(facetlist)
         totvertices += qh_setsize(qh, facet->vertices);
       if (totvneighbors != totvertices) {
         qh_fprintf(qh, qh->ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent.  Totvneighbors %d, totvertices %d\n",
                 totvneighbors, totvertices);
         waserror= True;
       }
     }
     if (numvertices != qh->num_vertices - qh_setsize(qh, qh->del_vertices)) {
       qh_fprintf(qh, qh->ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
               numvertices, qh->num_vertices - qh_setsize(qh, qh->del_vertices));
       waserror= True;
     }
     if (qh->hull_dim == 2 && numvertices != numfacets) {
       qh_fprintf(qh, qh->ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
         numvertices, numfacets);
       waserror= True;
     }
     if (qh->hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
       qh_fprintf(qh, qh->ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\
         A vertex appears twice in a edge list.  May occur during merging.",
         numvertices, numfacets, numridges/2);
       /* occurs if lots of merging and a vertex ends up twice in an edge list.  e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */
     }
   }
   if (waserror)
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
 } /* checkpolygon */
 
 
 /*---------------------------------
 
   qh_checkvertex(qh, vertex )
     check vertex for consistency
     checks vertex->neighbors
 
   notes:
     neighbors checked efficiently in checkpolygon
 */
 void qh_checkvertex(qhT *qh, vertexT *vertex) {
   boolT waserror= False;
   facetT *neighbor, **neighborp, *errfacet=NULL;
 
   if (qh_pointid(qh, vertex->point) == -1) {
     qh_fprintf(qh, qh->ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
     waserror= True;
   }
   if (vertex->id >= qh->vertex_id) {
     qh_fprintf(qh, qh->ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);
     waserror= True;
   }
   if (!waserror && !vertex->deleted) {
     if (qh_setsize(qh, vertex->neighbors)) {
       FOREACHneighbor_(vertex) {
         if (!qh_setin(neighbor->vertices, vertex)) {
           qh_fprintf(qh, qh->ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
           errfacet= neighbor;
           waserror= True;
         }
       }
     }
   }
   if (waserror) {
     qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
     qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
   }
 } /* checkvertex */
 
 /*---------------------------------
 
   qh_clearcenters(qh, type )
     clear old data from facet->center
 
   notes:
     sets new centertype
     nop if CENTERtype is the same
 */
 void qh_clearcenters(qhT *qh, qh_CENTER type) {
   facetT *facet;
 
   if (qh->CENTERtype != type) {
     FORALLfacets {
       if (facet->tricoplanar && !facet->keepcentrum)
           facet->center= NULL;
       else if (qh->CENTERtype == qh_ASvoronoi){
         if (facet->center) {
           qh_memfree(qh, facet->center, qh->center_size);
           facet->center= NULL;
         }
       }else /* qh->CENTERtype == qh_AScentrum */ {
         if (facet->center) {
           qh_memfree(qh, facet->center, qh->normal_size);
           facet->center= NULL;
         }
       }
     }
     qh->CENTERtype= type;
   }
   trace2((qh, qh->ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));
 } /* clearcenters */
 
 /*---------------------------------
 
   qh_createsimplex(qh, vertices )
     creates a simplex from a set of vertices
 
   returns:
     initializes qh.facet_list to the simplex
     initializes qh.newfacet_list, .facet_tail
     initializes qh.vertex_list, .newvertex_list, .vertex_tail
 
   design:
     initializes lists
     for each vertex
       create a new facet
     for each new facet
       create its neighbor set
 */
 void qh_createsimplex(qhT *qh, setT *vertices) {
   facetT *facet= NULL, *newfacet;
   boolT toporient= True;
   int vertex_i, vertex_n, nth;
   setT *newfacets= qh_settemp(qh, qh->hull_dim+1);
   vertexT *vertex;
 
   qh->facet_list= qh->newfacet_list= qh->facet_tail= qh_newfacet(qh);
   qh->num_facets= qh->num_vertices= qh->num_visible= 0;
   qh->vertex_list= qh->newvertex_list= qh->vertex_tail= qh_newvertex(qh, NULL);
   FOREACHvertex_i_(qh, vertices) {
     newfacet= qh_newfacet(qh);
     newfacet->vertices= qh_setnew_delnthsorted(qh, vertices, vertex_n,
                                                 vertex_i, 0);
     newfacet->toporient= (unsigned char)toporient;
     qh_appendfacet(qh, newfacet);
     newfacet->newfacet= True;
     qh_appendvertex(qh, vertex);
     qh_setappend(qh, &newfacets, newfacet);
     toporient ^= True;
   }
   FORALLnew_facets {
     nth= 0;
     FORALLfacet_(qh->newfacet_list) {
       if (facet != newfacet)
         SETelem_(newfacet->neighbors, nth++)= facet;
     }
     qh_settruncate(qh, newfacet->neighbors, qh->hull_dim);
   }
   qh_settempfree(qh, &newfacets);
   trace1((qh, qh->ferr, 1028, "qh_createsimplex: created simplex\n"));
 } /* createsimplex */
 
 /*---------------------------------
 
   qh_delridge(qh, ridge )
     deletes ridge from data structures it belongs to
     frees up its memory
 
   notes:
     in merge_r.c, caller sets vertex->delridge for each vertex
     ridges also freed in qh_freeqhull
 */
 void qh_delridge(qhT *qh, ridgeT *ridge) {
   void **freelistp; /* used !qh_NOmem */
 
   qh_setdel(ridge->top->ridges, ridge);
   qh_setdel(ridge->bottom->ridges, ridge);
   qh_setfree(qh, &(ridge->vertices));
   qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
 } /* delridge */
 
 
 /*---------------------------------
 
   qh_delvertex(qh, vertex )
     deletes a vertex and frees its memory
 
   notes:
     assumes vertex->adjacencies have been updated if needed
     unlinks from vertex_list
 */
 void qh_delvertex(qhT *qh, vertexT *vertex) {
 
   if (vertex == qh->tracevertex)
     qh->tracevertex= NULL;
   qh_removevertex(qh, vertex);
   qh_setfree(qh, &vertex->neighbors);
   qh_memfree(qh, vertex, (int)sizeof(vertexT));
 } /* delvertex */
 
 
 /*---------------------------------
 
   qh_facet3vertex(qh, )
     return temporary set of 3-d vertices in qh_ORIENTclock order
 
   design:
     if simplicial facet
       build set from facet->vertices with facet->toporient
     else
       for each ridge in order
         build set from ridge's vertices
 */
 setT *qh_facet3vertex(qhT *qh, facetT *facet) {
   ridgeT *ridge, *firstridge;
   vertexT *vertex;
   int cntvertices, cntprojected=0;
   setT *vertices;
 
   cntvertices= qh_setsize(qh, facet->vertices);
   vertices= qh_settemp(qh, cntvertices);
   if (facet->simplicial) {
     if (cntvertices != 3) {
       qh_fprintf(qh, qh->ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",
                   cntvertices, facet->id);
       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     }
     qh_setappend(qh, &vertices, SETfirst_(facet->vertices));
     if (facet->toporient ^ qh_ORIENTclock)
       qh_setappend(qh, &vertices, SETsecond_(facet->vertices));
     else
       qh_setaddnth(qh, &vertices, 0, SETsecond_(facet->vertices));
     qh_setappend(qh, &vertices, SETelem_(facet->vertices, 2));
   }else {
     ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
     while ((ridge= qh_nextridge3d(qh, ridge, facet, &vertex))) {
       qh_setappend(qh, &vertices, vertex);
       if (++cntprojected > cntvertices || ridge == firstridge)
         break;
     }
     if (!ridge || cntprojected != cntvertices) {
       qh_fprintf(qh, qh->ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n",
                   facet->id, cntprojected);
       qh_errexit(qh, qh_ERRqhull, facet, ridge);
     }
   }
   return vertices;
 } /* facet3vertex */
 
 /*---------------------------------
 
   qh_findbestfacet(qh, point, bestoutside, bestdist, isoutside )
     find facet that is furthest below a point
 
     for Delaunay triangulations,
       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
 
   returns:
     if bestoutside is set (e.g., qh_ALL)
       returns best facet that is not upperdelaunay
       if Delaunay and inside, point is outside circumsphere of bestfacet
     else
       returns first facet below point
       if point is inside, returns nearest, !upperdelaunay facet
     distance to facet
     isoutside set if outside of facet
 
   notes:
     For tricoplanar facets, this finds one of the tricoplanar facets closest
     to the point.  For Delaunay triangulations, the point may be inside a
     different tricoplanar facet. See locate a facet with qh_findbestfacet()
 
     If inside, qh_findbestfacet performs an exhaustive search
        this may be too conservative.  Sometimes it is clearly required.
 
     qh_findbestfacet is not used by qhull.
     uses qh.visit_id and qh.coplanarset
 
   see:
     qh_findbest
 */
 facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
            realT *bestdist, boolT *isoutside) {
   facetT *bestfacet= NULL;
   int numpart, totpart= 0;
 
   bestfacet= qh_findbest(qh, point, qh->facet_list,
                             bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
                             bestdist, isoutside, &totpart);
   if (*bestdist < -qh->DISTround) {
     bestfacet= qh_findfacet_all(qh, point, bestdist, isoutside, &numpart);
     totpart += numpart;
     if ((isoutside && bestoutside)
     || (!isoutside && bestfacet->upperdelaunay)) {
       bestfacet= qh_findbest(qh, point, bestfacet,
                             bestoutside, False, bestoutside,
                             bestdist, isoutside, &totpart);
       totpart += numpart;
     }
   }
   trace3((qh, qh->ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
           bestfacet->id, *bestdist, *isoutside, totpart));
   return bestfacet;
 } /* findbestfacet */
 
 /*---------------------------------
 
   qh_findbestlower(qh, facet, point, bestdist, numpart )
     returns best non-upper, non-flipped neighbor of facet for point
     if needed, searches vertex neighbors
 
   returns:
     returns bestdist and updates numpart
 
   notes:
     if Delaunay and inside, point is outside of circumsphere of bestfacet
     called by qh_findbest() for points above an upperdelaunay facet
 
 */
 facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {
   facetT *neighbor, **neighborp, *bestfacet= NULL;
   realT bestdist= -REALmax/2 /* avoid underflow */;
   realT dist;
   vertexT *vertex;
 
   zinc_(Zbestlower);
   FOREACHneighbor_(upperfacet) {
     if (neighbor->upperdelaunay || neighbor->flipped)
       continue;
     (*numpart)++;
     qh_distplane(qh, point, neighbor, &dist);
     if (dist > bestdist) {
       bestfacet= neighbor;
       bestdist= dist;
     }
   }
   if (!bestfacet) {
     zinc_(Zbestlowerv);
     /* rarely called, numpart does not count nearvertex computations */
     vertex= qh_nearvertex(qh, upperfacet, point, &dist);
     qh_vertexneighbors(qh);
     FOREACHneighbor_(vertex) {
       if (neighbor->upperdelaunay || neighbor->flipped)
         continue;
       (*numpart)++;
       qh_distplane(qh, point, neighbor, &dist);
       if (dist > bestdist) {
         bestfacet= neighbor;
         bestdist= dist;
       }
     }
   }
   if (!bestfacet) {
     qh_fprintf(qh, qh->ferr, 6228, "\n\
 Qhull internal error (qh_findbestlower): all neighbors of facet %d are flipped or upper Delaunay.\n\
 Please report this error to qhull_bug@qhull.org with the input and all of the output.\n",
        upperfacet->id);
     qh_errexit(qh, qh_ERRqhull, upperfacet, NULL);
   }
   *bestdistp= bestdist;
   trace3((qh, qh->ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",
           bestfacet->id, bestdist, upperfacet->id, qh_pointid(qh, point)));
   return bestfacet;
 } /* findbestlower */
 
 /*---------------------------------
 
   qh_findfacet_all(qh, point, bestdist, isoutside, numpart )
     exhaustive search for facet below a point
 
     for Delaunay triangulations,
       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
 
   returns:
     returns first facet below point
     if point is inside,
       returns nearest facet
     distance to facet
     isoutside if point is outside of the hull
     number of distance tests
 
   notes:
     for library users, not used by Qhull
 */
 facetT *qh_findfacet_all(qhT *qh, pointT *point, realT *bestdist, boolT *isoutside,
                           int *numpart) {
   facetT *bestfacet= NULL, *facet;
   realT dist;
   int totpart= 0;
 
   *bestdist= -REALmax;
   *isoutside= False;
   FORALLfacets {
     if (facet->flipped || !facet->normal)
       continue;
     totpart++;
     qh_distplane(qh, point, facet, &dist);
     if (dist > *bestdist) {
       *bestdist= dist;
       bestfacet= facet;
       if (dist > qh->MINoutside) {
         *isoutside= True;
         break;
       }
     }
   }
   *numpart= totpart;
   trace3((qh, qh->ferr, 3016, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",
           getid_(bestfacet), *bestdist, *isoutside, totpart));
   return bestfacet;
 } /* findfacet_all */
 
 /*---------------------------------
 
   qh_findgood(qh, facetlist, goodhorizon )
     identify good facets for qh.PRINTgood
     if qh.GOODvertex>0
       facet includes point as vertex
       if !match, returns goodhorizon
       inactive if qh.MERGING
     if qh.GOODpoint
       facet is visible or coplanar (>0) or not visible (<0)
     if qh.GOODthreshold
       facet->normal matches threshold
     if !goodhorizon and !match,
       selects facet with closest angle
       sets GOODclosest
 
   returns:
     number of new, good facets found
     determines facet->good
     may update qh.GOODclosest
 
   notes:
     qh_findgood_all further reduces the good region
 
   design:
     count good facets
     mark good facets for qh.GOODpoint
     mark good facets for qh.GOODthreshold
     if necessary
       update qh.GOODclosest
 */
 int qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon) {
   facetT *facet, *bestfacet= NULL;
   realT angle, bestangle= REALmax, dist;
   int  numgood=0;
 
   FORALLfacet_(facetlist) {
     if (facet->good)
       numgood++;
   }
   if (qh->GOODvertex>0 && !qh->MERGING) {
     FORALLfacet_(facetlist) {
       if (!qh_isvertex(qh, qh->GOODvertexp, facet->vertices)) {
         facet->good= False;
         numgood--;
       }
     }
   }
   if (qh->GOODpoint && numgood) {
     FORALLfacet_(facetlist) {
       if (facet->good && facet->normal) {
         zinc_(Zdistgood);
         qh_distplane(qh, qh->GOODpointp, facet, &dist);
         if ((qh->GOODpoint > 0) ^ (dist > 0.0)) {
           facet->good= False;
           numgood--;
         }
       }
     }
   }
   if (qh->GOODthreshold && (numgood || goodhorizon || qh->GOODclosest)) {
     FORALLfacet_(facetlist) {
       if (facet->good && facet->normal) {
         if (!qh_inthresholds(qh, facet->normal, &angle)) {
           facet->good= False;
           numgood--;
           if (angle < bestangle) {
             bestangle= angle;
             bestfacet= facet;
           }
         }
       }
     }
     if (!numgood && (!goodhorizon || qh->GOODclosest)) {
       if (qh->GOODclosest) {
         if (qh->GOODclosest->visible)
           qh->GOODclosest= NULL;
         else {
           qh_inthresholds(qh, qh->GOODclosest->normal, &angle);
           if (angle < bestangle)
             bestfacet= qh->GOODclosest;
         }
       }
       if (bestfacet && bestfacet != qh->GOODclosest) {
         if (qh->GOODclosest)
           qh->GOODclosest->good= False;
         qh->GOODclosest= bestfacet;
         bestfacet->good= True;
         numgood++;
         trace2((qh, qh->ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",
            bestfacet->id, bestangle));
         return numgood;
       }
     }else if (qh->GOODclosest) { /* numgood > 0 */
       qh->GOODclosest->good= False;
       qh->GOODclosest= NULL;
     }
   }
   zadd_(Zgoodfacet, numgood);
   trace2((qh, qh->ferr, 2045, "qh_findgood: found %d good facets with %d good horizon\n",
                numgood, goodhorizon));
   if (!numgood && qh->GOODvertex>0 && !qh->MERGING)
     return goodhorizon;
   return numgood;
 } /* findgood */
 
 /*---------------------------------
 
   qh_findgood_all(qh, facetlist )
     apply other constraints for good facets (used by qh.PRINTgood)
     if qh.GOODvertex
       facet includes (>0) or doesn't include (<0) point as vertex
       if last good facet and ONLYgood, prints warning and continues
     if qh.SPLITthresholds
       facet->normal matches threshold, or if none, the closest one
     calls qh_findgood
     nop if good not used
 
   returns:
     clears facet->good if not good
     sets qh.num_good
 
   notes:
     this is like qh_findgood but more restrictive
 
   design:
     uses qh_findgood to mark good facets
     marks facets for qh.GOODvertex
     marks facets for qh.SPLITthreholds
 */
 void qh_findgood_all(qhT *qh, facetT *facetlist) {
   facetT *facet, *bestfacet=NULL;
   realT angle, bestangle= REALmax;
   int  numgood=0, startgood;
 
   if (!qh->GOODvertex && !qh->GOODthreshold && !qh->GOODpoint
   && !qh->SPLITthresholds)
     return;
   if (!qh->ONLYgood)
     qh_findgood(qh, qh->facet_list, 0);
   FORALLfacet_(facetlist) {
     if (facet->good)
       numgood++;
   }
   if (qh->GOODvertex <0 || (qh->GOODvertex > 0 && qh->MERGING)) {
     FORALLfacet_(facetlist) {
       if (facet->good && ((qh->GOODvertex > 0) ^ !!qh_isvertex(qh, qh->GOODvertexp, facet->vertices))) {
         if (!--numgood) {
           if (qh->ONLYgood) {
             qh_fprintf(qh, qh->ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
                qh_pointid(qh, qh->GOODvertexp), facet->id);
             return;
           }else if (qh->GOODvertex > 0)
             qh_fprintf(qh, qh->ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",
                 qh->GOODvertex-1, qh->GOODvertex-1);
           else
             qh_fprintf(qh, qh->ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",
                 -qh->GOODvertex - 1, -qh->GOODvertex - 1);
         }
         facet->good= False;
       }
     }
   }
   startgood= numgood;
   if (qh->SPLITthresholds) {
     FORALLfacet_(facetlist) {
       if (facet->good) {
         if (!qh_inthresholds(qh, facet->normal, &angle)) {
           facet->good= False;
           numgood--;
           if (angle < bestangle) {
             bestangle= angle;
             bestfacet= facet;
           }
         }
       }
     }
     if (!numgood && bestfacet) {
       bestfacet->good= True;
       numgood++;
       trace0((qh, qh->ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to thresholds\n",
            bestfacet->id, bestangle));
       return;
     }
   }
   qh->num_good= numgood;
   trace0((qh, qh->ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",
         numgood, startgood));
 } /* findgood_all */
 
 /*---------------------------------
 
   qh_furthestnext()
     set qh.facet_next to facet with furthest of all furthest points
     searches all facets on qh.facet_list
 
   notes:
     this may help avoid precision problems
 */
 void qh_furthestnext(qhT *qh /* qh->facet_list */) {
   facetT *facet, *bestfacet= NULL;
   realT dist, bestdist= -REALmax;
 
   FORALLfacets {
     if (facet->outsideset) {
 #if qh_COMPUTEfurthest
       pointT *furthest;
       furthest= (pointT*)qh_setlast(facet->outsideset);
       zinc_(Zcomputefurthest);
       qh_distplane(qh, furthest, facet, &dist);
 #else
       dist= facet->furthestdist;
 #endif
       if (dist > bestdist) {
         bestfacet= facet;
         bestdist= dist;
       }
     }
   }
   if (bestfacet) {
     qh_removefacet(qh, bestfacet);
     qh_prependfacet(qh, bestfacet, &qh->facet_next);
     trace1((qh, qh->ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",
             bestfacet->id, bestdist));
   }
 } /* furthestnext */
 
 /*---------------------------------
 
   qh_furthestout(qh, facet )
     make furthest outside point the last point of outsideset
 
   returns:
     updates facet->outsideset
     clears facet->notfurthest
     sets facet->furthestdist
 
   design:
     determine best point of outsideset
     make it the last point of outsideset
 */
 void qh_furthestout(qhT *qh, facetT *facet) {
   pointT *point, **pointp, *bestpoint= NULL;
   realT dist, bestdist= -REALmax;
 
   FOREACHpoint_(facet->outsideset) {
     qh_distplane(qh, point, facet, &dist);
     zinc_(Zcomputefurthest);
     if (dist > bestdist) {
       bestpoint= point;
       bestdist= dist;
     }
   }
   if (bestpoint) {
     qh_setdel(facet->outsideset, point);
     qh_setappend(qh, &facet->outsideset, point);
 #if !qh_COMPUTEfurthest
     facet->furthestdist= bestdist;
 #endif
   }
   facet->notfurthest= False;
   trace3((qh, qh->ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",
           qh_pointid(qh, point), facet->id));
 } /* furthestout */
 
 
 /*---------------------------------
 
   qh_infiniteloop(qh, facet )
     report infinite loop error due to facet
 */
 void qh_infiniteloop(qhT *qh, facetT *facet) {
 
   qh_fprintf(qh, qh->ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");
   qh_errexit(qh, qh_ERRqhull, facet, NULL);
 } /* qh_infiniteloop */
 
 /*---------------------------------
 
   qh_initbuild()
     initialize hull and outside sets with point array
     qh.FIRSTpoint/qh.NUMpoints is point array
     if qh.GOODpoint
       adds qh.GOODpoint to initial hull
 
   returns:
     qh_facetlist with initial hull
     points partioned into outside sets, coplanar sets, or inside
     initializes qh.GOODpointp, qh.GOODvertexp,
 
   design:
     initialize global variables used during qh_buildhull
     determine precision constants and points with max/min coordinate values
       if qh.SCALElast, scale last coordinate(for 'd')
     build initial simplex
     partition input points into facets of initial simplex
     set up lists
     if qh.ONLYgood
       check consistency
       add qh.GOODvertex if defined
 */
 void qh_initbuild(qhT *qh) {
   setT *maxpoints, *vertices;
   facetT *facet;
   int i, numpart;
   realT dist;
   boolT isoutside;
 
   qh->furthest_id= -1;
   qh->lastreport= 0;
   qh->facet_id= qh->vertex_id= qh->ridge_id= 0;
   qh->visit_id= qh->vertex_visit= 0;
   qh->maxoutdone= False;
 
   if (qh->GOODpoint > 0)
     qh->GOODpointp= qh_point(qh, qh->GOODpoint-1);
   else if (qh->GOODpoint < 0)
     qh->GOODpointp= qh_point(qh, -qh->GOODpoint-1);
   if (qh->GOODvertex > 0)
     qh->GOODvertexp= qh_point(qh, qh->GOODvertex-1);
   else if (qh->GOODvertex < 0)
     qh->GOODvertexp= qh_point(qh, -qh->GOODvertex-1);
   if ((qh->GOODpoint
        && (qh->GOODpointp < qh->first_point  /* also catches !GOODpointp */
            || qh->GOODpointp > qh_point(qh, qh->num_points-1)))
     || (qh->GOODvertex
         && (qh->GOODvertexp < qh->first_point  /* also catches !GOODvertexp */
             || qh->GOODvertexp > qh_point(qh, qh->num_points-1)))) {
     qh_fprintf(qh, qh->ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",
              qh->num_points-1);
     qh_errexit(qh, qh_ERRinput, NULL, NULL);
   }
   maxpoints= qh_maxmin(qh, qh->first_point, qh->num_points, qh->hull_dim);
   if (qh->SCALElast)
     qh_scalelast(qh, qh->first_point, qh->num_points, qh->hull_dim,
                qh->MINlastcoord, qh->MAXlastcoord, qh->MAXwidth);
   qh_detroundoff(qh);
   if (qh->DELAUNAY && qh->upper_threshold[qh->hull_dim-1] > REALmax/2
                   && qh->lower_threshold[qh->hull_dim-1] < -REALmax/2) {
     for (i=qh_PRINTEND; i--; ) {
       if (qh->PRINTout[i] == qh_PRINTgeom && qh->DROPdim < 0
           && !qh->GOODthreshold && !qh->SPLITthresholds)
         break;  /* in this case, don't set upper_threshold */
     }
     if (i < 0) {
       if (qh->UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
         qh->lower_threshold[qh->hull_dim-1]= qh->ANGLEround * qh_ZEROdelaunay;
         qh->GOODthreshold= True;
       }else {
         qh->upper_threshold[qh->hull_dim-1]= -qh->ANGLEround * qh_ZEROdelaunay;
         if (!qh->GOODthreshold)
           qh->SPLITthresholds= True; /* build upper-convex hull even if Qg */
           /* qh_initqhull_globals errors if Qg without Pdk/etc. */
       }
     }
   }
   vertices= qh_initialvertices(qh, qh->hull_dim, maxpoints, qh->first_point, qh->num_points);
   qh_initialhull(qh, vertices);  /* initial qh->facet_list */
   qh_partitionall(qh, vertices, qh->first_point, qh->num_points);
   if (qh->PRINToptions1st || qh->TRACElevel || qh->IStracing) {
     if (qh->TRACElevel || qh->IStracing)
       qh_fprintf(qh, qh->ferr, 8103, "\nTrace level %d for %s | %s\n",
          qh->IStracing ? qh->IStracing : qh->TRACElevel, qh->rbox_command, qh->qhull_command);
     qh_fprintf(qh, qh->ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
   }
   qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);
   qh->facet_next= qh->facet_list;
   qh_furthestnext(qh /* qh->facet_list */);
   if (qh->PREmerge) {
     qh->cos_max= qh->premerge_cos;
     qh->centrum_radius= qh->premerge_centrum;
   }
   if (qh->ONLYgood) {
     if (qh->GOODvertex > 0 && qh->MERGING) {
       qh_fprintf(qh, qh->ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     if (!(qh->GOODthreshold || qh->GOODpoint
          || (!qh->MERGEexact && !qh->PREmerge && qh->GOODvertexp))) {
       qh_fprintf(qh, qh->ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a\n\
 good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
       qh_errexit(qh, qh_ERRinput, NULL, NULL);
     }
     if (qh->GOODvertex > 0  && !qh->MERGING  /* matches qh_partitionall */
         && !qh_isvertex(qh, qh->GOODvertexp, vertices)) {
       facet= qh_findbestnew(qh, qh->GOODvertexp, qh->facet_list,
                           &dist, !qh_ALL, &isoutside, &numpart);
       zadd_(Zdistgood, numpart);
       if (!isoutside) {
         qh_fprintf(qh, qh->ferr, 6153, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
                qh_pointid(qh, qh->GOODvertexp));
         qh_errexit(qh, qh_ERRinput, NULL, NULL);
       }
       if (!qh_addpoint(qh, qh->GOODvertexp, facet, False)) {
         qh_settempfree(qh, &vertices);
         qh_settempfree(qh, &maxpoints);
         return;
       }
     }
     qh_findgood(qh, qh->facet_list, 0);
   }
   qh_settempfree(qh, &vertices);
   qh_settempfree(qh, &maxpoints);
   trace1((qh, qh->ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));
 } /* initbuild */
 
 /*---------------------------------
 
   qh_initialhull(qh, vertices )
     constructs the initial hull as a DIM3 simplex of vertices
 
   design:
     creates a simplex (initializes lists)
     determines orientation of simplex
     sets hyperplanes for facets
     doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
     checks for flipped facets and qh.NARROWhull
     checks the result
 */
 void qh_initialhull(qhT *qh, setT *vertices) {
   facetT *facet, *firstfacet, *neighbor, **neighborp;
   realT dist, angle, minangle= REALmax;
 #ifndef qh_NOtrace
   int k;
 #endif
 
   qh_createsimplex(qh, vertices);  /* qh->facet_list */
   qh_resetlists(qh, False, qh_RESETvisible);
   qh->facet_next= qh->facet_list;      /* advance facet when processed */
   qh->interior_point= qh_getcenter(qh, vertices);
   firstfacet= qh->facet_list;
   qh_setfacetplane(qh, firstfacet);
   zinc_(Znumvisibility); /* needs to be in printsummary */
   qh_distplane(qh, qh->interior_point, firstfacet, &dist);
   if (dist > 0) {
     FORALLfacets
       facet->toporient ^= (unsigned char)True;
   }
   FORALLfacets
     qh_setfacetplane(qh, facet);
   FORALLfacets {
     if (!qh_checkflipped(qh, facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
       trace1((qh, qh->ferr, 1031, "qh_initialhull: initial orientation incorrect.  Correct all facets\n"));
       facet->flipped= False;
       FORALLfacets {
         facet->toporient ^= (unsigned char)True;
         qh_orientoutside(qh, facet);
       }
       break;
     }
   }
   FORALLfacets {
     if (!qh_checkflipped(qh, facet, NULL, !qh_ALL)) {  /* can happen with 'R0.1' */
       if (qh->DELAUNAY && ! qh->ATinfinity) {
         if (qh->UPPERdelaunay)
           qh_fprintf(qh, qh->ferr, 6240, "Qhull input error: Can not compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");
         else
           qh_fprintf(qh, qh->ferr, 6239, "Qhull input error: Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points.  Option 'Qz' adds a point \"at infinity\" (above the corresponding paraboloid).\n");
         qh_errexit(qh, qh_ERRinput, NULL, NULL);
       }
       qh_precision(qh, "initial facet is coplanar with interior point");
       qh_fprintf(qh, qh->ferr, 6154, "qhull precision error: initial facet %d is coplanar with the interior point\n",
                    facet->id);
       qh_errexit(qh, qh_ERRsingular, facet, NULL);
     }
     FOREACHneighbor_(facet) {
       angle= qh_getangle(qh, facet->normal, neighbor->normal);
       minimize_( minangle, angle);
     }
   }
   if (minangle < qh_MAXnarrow && !qh->NOnarrow) {
     realT diff= 1.0 + minangle;
 
     qh->NARROWhull= True;
     qh_option(qh, "_narrow-hull", NULL, &diff);
     if (minangle < qh_WARNnarrow && !qh->RERUN && qh->PRINTprecision)
       qh_printhelp_narrowhull(qh, qh->ferr, minangle);
   }
   zzval_(Zprocessed)= qh->hull_dim+1;
   qh_checkpolygon(qh, qh->facet_list);
   qh_checkconvex(qh, qh->facet_list,   qh_DATAfault);
 #ifndef qh_NOtrace
   if (qh->IStracing >= 1) {
     qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: simplex constructed, interior point:");
     for (k=0; k < qh->hull_dim; k++)
       qh_fprintf(qh, qh->ferr, 8106, " %6.4g", qh->interior_point[k]);
     qh_fprintf(qh, qh->ferr, 8107, "\n");
   }
 #endif
 } /* initialhull */
 
 /*---------------------------------
 
   qh_initialvertices(qh, dim, maxpoints, points, numpoints )
     determines a non-singular set of initial vertices
     maxpoints may include duplicate points
 
   returns:
     temporary set of dim+1 vertices in descending order by vertex id
     if qh.RANDOMoutside && !qh.ALLpoints
       picks random points
     if dim >= qh_INITIALmax,
       uses min/max x and max points with non-zero determinants
 
   notes:
     unless qh.ALLpoints,
       uses maxpoints as long as determinate is non-zero
 */
 setT *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints) {
   pointT *point, **pointp;
   setT *vertices, *simplex, *tested;
   realT randr;
   int idx, point_i, point_n, k;
   boolT nearzero= False;
 
   vertices= qh_settemp(qh, dim + 1);
   simplex= qh_settemp(qh, dim+1);
   if (qh->ALLpoints)
     qh_maxsimplex(qh, dim, NULL, points, numpoints, &simplex);
   else if (qh->RANDOMoutside) {
     while (qh_setsize(qh, simplex) != dim+1) {
       randr= qh_RANDOMint;
       randr= randr/(qh_RANDOMmax+1);
       idx= (int)floor(qh->num_points * randr);
       while (qh_setin(simplex, qh_point(qh, idx))) {
             idx++; /* in case qh_RANDOMint always returns the same value */
         idx= idx < qh->num_points ? idx : 0;
       }
       qh_setappend(qh, &simplex, qh_point(qh, idx));
     }
   }else if (qh->hull_dim >= qh_INITIALmax) {
     tested= qh_settemp(qh, dim+1);
     qh_setappend(qh, &simplex, SETfirst_(maxpoints));   /* max and min X coord */
     qh_setappend(qh, &simplex, SETsecond_(maxpoints));
     qh_maxsimplex(qh, fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
     k= qh_setsize(qh, simplex);
     FOREACHpoint_i_(qh, maxpoints) {
       if (point_i & 0x1) {     /* first pick up max. coord. points */
         if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
           qh_detsimplex(qh, point, simplex, k, &nearzero);
           if (nearzero)
             qh_setappend(qh, &tested, point);
           else {
             qh_setappend(qh, &simplex, point);
             if (++k == dim)  /* use search for last point */
               break;
           }
         }
       }
     }
     while (k != dim && (point= (pointT*)qh_setdellast(maxpoints))) {
       if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
         qh_detsimplex(qh, point, simplex, k, &nearzero);
         if (nearzero)
           qh_setappend(qh, &tested, point);
         else {
           qh_setappend(qh, &simplex, point);
           k++;
         }
       }
     }
     idx= 0;
     while (k != dim && (point= qh_point(qh, idx++))) {
       if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
         qh_detsimplex(qh, point, simplex, k, &nearzero);
         if (!nearzero){
           qh_setappend(qh, &simplex, point);
           k++;
         }
       }
     }
     qh_settempfree(qh, &tested);
     qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
   }else
     qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
   FOREACHpoint_(simplex)
     qh_setaddnth(qh, &vertices, 0, qh_newvertex(qh, point)); /* descending order */
   qh_settempfree(qh, &simplex);
   return vertices;
 } /* initialvertices */
 
 
 /*---------------------------------
 
   qh_isvertex(qh, )
     returns vertex if point is in vertex set, else returns NULL
 
   notes:
     for qh.GOODvertex
 */
 vertexT *qh_isvertex(qhT *qh, pointT *point, setT *vertices) {
   vertexT *vertex, **vertexp;
 
   FOREACHvertex_(vertices) {
     if (vertex->point == point)
       return vertex;
   }
   return NULL;
 } /* isvertex */
 
 /*---------------------------------
 
   qh_makenewfacets(qh, point )
     make new facets from point and qh.visible_list
 
   returns:
     qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
     qh.newvertex_list= list of vertices in new facets with ->newlist set
 
     if (qh.ONLYgood)
       newfacets reference horizon facets, but not vice versa
       ridges reference non-simplicial horizon ridges, but not vice versa
       does not change existing facets
     else
       sets qh.NEWfacets
       new facets attached to horizon facets and ridges
       for visible facets,
         visible->r.replace is corresponding new facet
 
   see also:
     qh_makenewplanes() -- make hyperplanes for facets
     qh_attachnewfacets() -- attachnewfacets if not done here(qh->ONLYgood)
     qh_matchnewfacets() -- match up neighbors
     qh_updatevertices() -- update vertex neighbors and delvertices
     qh_deletevisible() -- delete visible facets
     qh_checkpolygon() --check the result
     qh_triangulate() -- triangulate a non-simplicial facet
 
   design:
     for each visible facet
       make new facets to its horizon facets
       update its f.replace
       clear its neighbor set
 */
 vertexT *qh_makenewfacets(qhT *qh, pointT *point /*visible_list*/) {
   facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
   vertexT *apex;
   int numnew=0;
 
   qh->newfacet_list= qh->facet_tail;
   qh->newvertex_list= qh->vertex_tail;
   apex= qh_newvertex(qh, point);
   qh_appendvertex(qh, apex);
   qh->visit_id++;
   if (!qh->ONLYgood)
     qh->NEWfacets= True;
   FORALLvisible_facets {
     FOREACHneighbor_(visible)
       neighbor->seen= False;
     if (visible->ridges) {
       visible->visitid= qh->visit_id;
       newfacet2= qh_makenew_nonsimplicial(qh, visible, apex, &numnew);
     }
     if (visible->simplicial)
       newfacet= qh_makenew_simplicial(qh, visible, apex, &numnew);
     if (!qh->ONLYgood) {
       if (newfacet2)  /* newfacet is null if all ridges defined */
         newfacet= newfacet2;
       if (newfacet)
         visible->f.replace= newfacet;
       else
         zinc_(Zinsidevisible);
       SETfirst_(visible->neighbors)= NULL;
     }
   }
   trace1((qh, qh->ferr, 1032, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",
           numnew, qh_pointid(qh, point)));
   if (qh->IStracing >= 4)
     qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
   return apex;
 } /* makenewfacets */
 
 /*---------------------------------
 
   qh_matchduplicates(qh, atfacet, atskip, hashsize, hashcount )
     match duplicate ridges in qh.hash_table for atfacet/atskip
     duplicates marked with ->dupridge and qh_DUPLICATEridge
 
   returns:
     picks match with worst merge (min distance apart)
     updates hashcount
 
   see also:
     qh_matchneighbor
 
   notes:
 
   design:
     compute hash value for atfacet and atskip
     repeat twice -- once to make best matches, once to match the rest
       for each possible facet in qh.hash_table
         if it is a matching facet and pass 2
           make match
           unless tricoplanar, mark match for merging (qh_MERGEridge)
           [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
         if it is a matching facet and pass 1
           test if this is a better match
       if pass 1,
         make best match (it will not be merged)
 */
 #ifndef qh_NOmerge
 void qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
   boolT same, ismatch;
   int hash, scan;
   facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;
   int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;
   realT maxdist= -REALmax, mindist, dist2, low, high;
 
   hash= qh_gethash(qh, hashsize, atfacet->vertices, qh->hull_dim, 1,
                      SETelem_(atfacet->vertices, atskip));
   trace2((qh, qh->ferr, 2046, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",
           atfacet->id, atskip, hash, *hashcount));
   for (makematch= 0; makematch < 2; makematch++) {
     qh->visit_id++;
     for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
       zinc_(Zhashlookup);
       nextfacet= NULL;
       newfacet->visitid= qh->visit_id;
       for (scan= hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
            scan= (++scan >= hashsize ? 0 : scan)) {
         if (!facet->dupridge || facet->visitid == qh->visit_id)
           continue;
         zinc_(Zhashtests);
         if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
           ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));
           if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
             if (!makematch) {
               qh_fprintf(qh, qh->ferr, 6155, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",
                      facet->id, skip, newfacet->id, newskip, hash);
               qh_errexit2(qh, qh_ERRqhull, facet, newfacet);
             }
           }else if (ismatch && makematch) {
             if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
               SETelem_(facet->neighbors, skip)= newfacet;
               if (newfacet->tricoplanar)
                 SETelem_(newfacet->neighbors, newskip)= facet;
               else
                 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
               *hashcount -= 2; /* removed two unmatched facets */
               trace4((qh, qh->ferr, 4059, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",
                     facet->id, skip, newfacet->id, newskip));
             }
           }else if (ismatch) {
             mindist= qh_getdistance(qh, facet, newfacet, &low, &high);
             dist2= qh_getdistance(qh, newfacet, facet, &low, &high);
             minimize_(mindist, dist2);
             if (mindist > maxdist) {
               maxdist= mindist;
               maxmatch= facet;
               maxskip= skip;
               maxmatch2= newfacet;
               maxskip2= newskip;
             }
             trace3((qh, qh->ferr, 3018, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",
                     facet->id, skip, newfacet->id, newskip, mindist,
                     maxmatch->id, maxmatch2->id));
           }else { /* !ismatch */
             nextfacet= facet;
             nextskip= skip;
           }
         }
         if (makematch && !facet
         && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {
           qh_fprintf(qh, qh->ferr, 6156, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",
                      newfacet->id, newskip, hash);
           qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
         }
       }
     } /* end of for each new facet at hash */
     if (!makematch) {
       if (!maxmatch) {
         qh_fprintf(qh, qh->ferr, 6157, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",
                      atfacet->id, atskip, hash);
         qh_errexit(qh, qh_ERRqhull, atfacet, NULL);
       }
       SETelem_(maxmatch->neighbors, maxskip)= maxmatch2;
       SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
       *hashcount -= 2; /* removed two unmatched facets */
       zzinc_(Zmultiridge);
       trace0((qh, qh->ferr, 25, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",
               maxmatch->id, maxskip, maxmatch2->id, maxskip2));
       qh_precision(qh, "ridge with multiple neighbors");
       if (qh->IStracing >= 4)
         qh_errprint(qh, "DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);
     }
   }
 } /* matchduplicates */
 
 /*---------------------------------
 
   qh_nearcoplanar()
     for all facets, remove near-inside points from facet->coplanarset
     coplanar points defined by innerplane from qh_outerinner()
 
   returns:
     if qh->KEEPcoplanar && !qh->KEEPinside
       facet->coplanarset only contains coplanar points
     if qh.JOGGLEmax
       drops inner plane by another qh.JOGGLEmax diagonal since a
         vertex could shift out while a coplanar point shifts in
 
   notes:
     used for qh.PREmerge and qh.JOGGLEmax
     must agree with computation of qh.NEARcoplanar in qh_detroundoff(qh)
   design:
     if not keeping coplanar or inside points
       free all coplanar sets
     else if not keeping both coplanar and inside points
       remove !coplanar or !inside points from coplanar sets
 */
 void qh_nearcoplanar(qhT *qh /* qh.facet_list */) {
   facetT *facet;
   pointT *point, **pointp;
   int numpart;
   realT dist, innerplane;
 
   if (!qh->KEEPcoplanar && !qh->KEEPinside) {
     FORALLfacets {
       if (facet->coplanarset)
         qh_setfree(qh, &facet->coplanarset);
     }
   }else if (!qh->KEEPcoplanar || !qh->KEEPinside) {
     qh_outerinner(qh, NULL, NULL, &innerplane);
     if (qh->JOGGLEmax < REALmax/2)
       innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
     numpart= 0;
     FORALLfacets {
       if (facet->coplanarset) {
         FOREACHpoint_(facet->coplanarset) {
           numpart++;
           qh_distplane(qh, point, facet, &dist);
           if (dist < innerplane) {
             if (!qh->KEEPinside)
               SETref_(point)= NULL;
           }else if (!qh->KEEPcoplanar)
             SETref_(point)= NULL;
         }
         qh_setcompact(qh, facet->coplanarset);
       }
     }
     zzadd_(Zcheckpart, numpart);
   }
 } /* nearcoplanar */
 
 /*---------------------------------
 
   qh_nearvertex(qh, facet, point, bestdist )
     return nearest vertex in facet to point
 
   returns:
     vertex and its distance
 
   notes:
     if qh.DELAUNAY
       distance is measured in the input set
     searches neighboring tricoplanar facets (requires vertexneighbors)
       Slow implementation.  Recomputes vertex set for each point.
     The vertex set could be stored in the qh.keepcentrum facet.
 */
 vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp) {
   realT bestdist= REALmax, dist;
   vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
   coordT *center;
   facetT *neighbor, **neighborp;
   setT *vertices;
   int dim= qh->hull_dim;
 
   if (qh->DELAUNAY)
     dim--;
   if (facet->tricoplanar) {
     if (!qh->VERTEXneighbors || !facet->center) {
       qh_fprintf(qh, qh->ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     }
     vertices= qh_settemp(qh, qh->TEMPsize);
     apex= SETfirstt_(facet->vertices, vertexT);
     center= facet->center;
     FOREACHneighbor_(apex) {
       if (neighbor->center == center) {
         FOREACHvertex_(neighbor->vertices)
           qh_setappend(qh, &vertices, vertex);
       }
     }
   }else
     vertices= facet->vertices;
   FOREACHvertex_(vertices) {
     dist= qh_pointdist(qh, vertex->point, point, -dim);
     if (dist < bestdist) {
       bestdist= dist;
       bestvertex= vertex;
     }
   }
   if (facet->tricoplanar)
     qh_settempfree(qh, &vertices);
   *bestdistp= sqrt(bestdist);
   trace3((qh, qh->ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",
         bestvertex->id, *bestdistp, facet->id, qh_pointid(qh, point)));
   return bestvertex;
 } /* nearvertex */
 
 /*---------------------------------
 
   qh_newhashtable(qh, newsize )
     returns size of qh.hash_table of at least newsize slots
 
   notes:
     assumes qh.hash_table is NULL
     qh_HASHfactor determines the number of extra slots
     size is not divisible by 2, 3, or 5
 */
 int qh_newhashtable(qhT *qh, int newsize) {
   int size;
 
   size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
   while (True) {
     if (newsize<0 || size<0) {
         qh_fprintf(qh, qh->qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d).  Did int overflow due to high-D?\n", newsize, size); /* WARN64 */
         qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
     }
     if ((size%3) && (size%5))
       break;
     size += 2;
     /* loop terminates because there is an infinite number of primes */
   }
   qh->hash_table= qh_setnew(qh, size);
   qh_setzero(qh, qh->hash_table, 0, size);
   return size;
 } /* newhashtable */
 
 /*---------------------------------
 
   qh_newvertex(qh, point )
     returns a new vertex for point
 */
 vertexT *qh_newvertex(qhT *qh, pointT *point) {
   vertexT *vertex;
 
   zinc_(Ztotvertices);
   vertex= (vertexT *)qh_memalloc(qh, (int)sizeof(vertexT));
   memset((char *) vertex, (size_t)0, sizeof(vertexT));
   if (qh->vertex_id == 0xFFFFFF) {
     qh_fprintf(qh, qh->ferr, 6159, "qhull error: more than %d vertices.  ID field overflows and two vertices\n\
 may have the same identifier.  Vertices will not be sorted correctly.\n", 0xFFFFFF);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   if (qh->vertex_id == qh->tracevertex_id)
     qh->tracevertex= vertex;
   vertex->id= qh->vertex_id++;
   vertex->point= point;
   trace4((qh, qh->ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(qh, vertex->point),
           vertex->id));
   return(vertex);
 } /* newvertex */
 
 /*---------------------------------
 
   qh_nextridge3d(qh, atridge, facet, vertex )
     return next ridge and vertex for a 3d facet
     returns NULL on error
     [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qhT.
 
   notes:
     in qh_ORIENTclock order
     this is a O(n^2) implementation to trace all ridges
     be sure to stop on any 2nd visit
     same as QhullRidge::nextRidge3d
     does not use qhT or qh_errexit [QhullFacet.cpp]
 
   design:
     for each ridge
       exit if it is the ridge after atridge
 */
 ridgeT *qh_nextridge3d(qhT *qh, ridgeT *atridge, facetT *facet, vertexT **vertexp) {
   vertexT *atvertex, *vertex, *othervertex;
   ridgeT *ridge, **ridgep;
 
   if ((atridge->top == facet) ^ qh_ORIENTclock)
     atvertex= SETsecondt_(atridge->vertices, vertexT);
   else
     atvertex= SETfirstt_(atridge->vertices, vertexT);
   FOREACHridge_(facet->ridges) {
     if (ridge == atridge)
       continue;
     if ((ridge->top == facet) ^ qh_ORIENTclock) {
       othervertex= SETsecondt_(ridge->vertices, vertexT);
       vertex= SETfirstt_(ridge->vertices, vertexT);
     }else {
       vertex= SETsecondt_(ridge->vertices, vertexT);
       othervertex= SETfirstt_(ridge->vertices, vertexT);
     }
     if (vertex == atvertex) {
       if (vertexp)
         *vertexp= othervertex;
       return ridge;
     }
   }
   return NULL;
 } /* nextridge3d */
 #else /* qh_NOmerge */
 void qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
 }
 ridgeT *qh_nextridge3d(qhT *qh, ridgeT *atridge, facetT *facet, vertexT **vertexp) {
 
   return NULL;
 }
 #endif /* qh_NOmerge */
 
 /*---------------------------------
 
   qh_outcoplanar()
     move points from all facets' outsidesets to their coplanarsets
 
   notes:
     for post-processing under qh.NARROWhull
 
   design:
     for each facet
       for each outside point for facet
         partition point into coplanar set
 */
 void qh_outcoplanar(qhT *qh /* facet_list */) {
   pointT *point, **pointp;
   facetT *facet;
   realT dist;
 
   trace1((qh, qh->ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh->NARROWhull\n"));
   FORALLfacets {
     FOREACHpoint_(facet->outsideset) {
       qh->num_outside--;
       if (qh->KEEPcoplanar || qh->KEEPnearinside) {
         qh_distplane(qh, point, facet, &dist);
         zinc_(Zpartition);
         qh_partitioncoplanar(qh, point, facet, &dist);
       }
     }
     qh_setfree(qh, &facet->outsideset);
   }
 } /* outcoplanar */
 
 /*---------------------------------
 
   qh_point(qh, id )
     return point for a point id, or NULL if unknown
 
   alternative code:
     return((pointT *)((unsigned   long)qh.first_point
            + (unsigned long)((id)*qh.normal_size)));
 */
 pointT *qh_point(qhT *qh, int id) {
 
   if (id < 0)
     return NULL;
   if (id < qh->num_points)
     return qh->first_point + id * qh->hull_dim;
   id -= qh->num_points;
   if (id < qh_setsize(qh, qh->other_points))
     return SETelemt_(qh->other_points, id, pointT);
   return NULL;
 } /* point */
 
 /*---------------------------------
 
   qh_point_add(qh, set, point, elem )
     stores elem at set[point.id]
 
   returns:
     access function for qh_pointfacet and qh_pointvertex
 
   notes:
     checks point.id
 */
 void qh_point_add(qhT *qh, setT *set, pointT *point, void *elem) {
   int id, size;
 
   SETreturnsize_(set, size);
   if ((id= qh_pointid(qh, point)) < 0)
     qh_fprintf(qh, qh->ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",
       point, id);
   else if (id >= size) {
     qh_fprintf(qh, qh->ferr, 6160, "qhull internal errror(point_add): point p%d is out of bounds(%d)\n",
              id, size);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }else
     SETelem_(set, id)= elem;
 } /* point_add */
 
 
 /*---------------------------------
 
   qh_pointfacet()
     return temporary set of facet for each point
     the set is indexed by point id
 
   notes:
     vertices assigned to one of the facets
     coplanarset assigned to the facet
     outside set assigned to the facet
     NULL if no facet for point (inside)
       includes qh.GOODpointp
 
   access:
     FOREACHfacet_i_(qh, facets) { ... }
     SETelem_(facets, i)
 
   design:
     for each facet
       add each vertex
       add each coplanar point
       add each outside point
 */
 setT *qh_pointfacet(qhT *qh /*qh.facet_list*/) {
   int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
   setT *facets;
   facetT *facet;
   vertexT *vertex, **vertexp;
   pointT *point, **pointp;
 
   facets= qh_settemp(qh, numpoints);
   qh_setzero(qh, facets, 0, numpoints);
   qh->vertex_visit++;
   FORALLfacets {
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh->vertex_visit) {
         vertex->visitid= qh->vertex_visit;
         qh_point_add(qh, facets, vertex->point, facet);
       }
     }
     FOREACHpoint_(facet->coplanarset)
       qh_point_add(qh, facets, point, facet);
     FOREACHpoint_(facet->outsideset)
       qh_point_add(qh, facets, point, facet);
   }
   return facets;
 } /* pointfacet */
 
 /*---------------------------------
 
   qh_pointvertex(qh, )
     return temporary set of vertices indexed by point id
     entry is NULL if no vertex for a point
       this will include qh.GOODpointp
 
   access:
     FOREACHvertex_i_(qh, vertices) { ... }
     SETelem_(vertices, i)
 */
 setT *qh_pointvertex(qhT *qh /*qh.facet_list*/) {
   int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
   setT *vertices;
   vertexT *vertex;
 
   vertices= qh_settemp(qh, numpoints);
   qh_setzero(qh, vertices, 0, numpoints);
   FORALLvertices
     qh_point_add(qh, vertices, vertex->point, vertex);
   return vertices;
 } /* pointvertex */
 
 
 /*---------------------------------
 
   qh_prependfacet(qh, facet, facetlist )
     prepend facet to the start of a facetlist
 
   returns:
     increments qh.numfacets
     updates facetlist, qh.facet_list, facet_next
 
   notes:
     be careful of prepending since it can lose a pointer.
       e.g., can lose _next by deleting and then prepending before _next
 */
 void qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist) {
   facetT *prevfacet, *list;
 
 
   trace4((qh, qh->ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",
           facet->id, getid_(*facetlist)));
   if (!*facetlist)
     (*facetlist)= qh->facet_tail;
   list= *facetlist;
   prevfacet= list->previous;
   facet->previous= prevfacet;
   if (prevfacet)
     prevfacet->next= facet;
   list->previous= facet;
   facet->next= *facetlist;
   if (qh->facet_list == list)  /* this may change *facetlist */
     qh->facet_list= facet;
   if (qh->facet_next == list)
     qh->facet_next= facet;
   *facetlist= facet;
   qh->num_facets++;
 } /* prependfacet */
 
 
 /*---------------------------------
 
   qh_printhashtable(qh, fp )
     print hash table to fp
 
   notes:
     not in I/O to avoid bringing io_r.c in
 
   design:
     for each hash entry
       if defined
         if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
           print entry and neighbors
 */
 void qh_printhashtable(qhT *qh, FILE *fp) {
   facetT *facet, *neighbor;
   int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
   vertexT *vertex, **vertexp;
 
   FOREACHfacet_i_(qh, qh->hash_table) {
     if (facet) {
       FOREACHneighbor_i_(qh, facet) {
         if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
           break;
       }
       if (neighbor_i == neighbor_n)
         continue;
       qh_fprintf(qh, fp, 9283, "hash %d f%d ", facet_i, facet->id);
       FOREACHvertex_(facet->vertices)
         qh_fprintf(qh, fp, 9284, "v%d ", vertex->id);
       qh_fprintf(qh, fp, 9285, "\n neighbors:");
       FOREACHneighbor_i_(qh, facet) {
         if (neighbor == qh_MERGEridge)
           id= -3;
         else if (neighbor == qh_DUPLICATEridge)
           id= -2;
         else
           id= getid_(neighbor);
         qh_fprintf(qh, fp, 9286, " %d", id);
       }
       qh_fprintf(qh, fp, 9287, "\n");
     }
   }
 } /* printhashtable */
 
 
 /*---------------------------------
 
   qh_printlists(qh, fp )
     print out facet and vertex list for debugging (without 'f/v' tags)
 */
 void qh_printlists(qhT *qh) {
   facetT *facet;
   vertexT *vertex;
   int count= 0;
 
   qh_fprintf(qh, qh->ferr, 8108, "qh_printlists: facets:");
   FORALLfacets {
     if (++count % 100 == 0)
       qh_fprintf(qh, qh->ferr, 8109, "\n     ");
     qh_fprintf(qh, qh->ferr, 8110, " %d", facet->id);
   }
   qh_fprintf(qh, qh->ferr, 8111, "\n  new facets %d visible facets %d next facet for qh_addpoint %d\n  vertices(new %d):",
      getid_(qh->newfacet_list), getid_(qh->visible_list), getid_(qh->facet_next),
      getid_(qh->newvertex_list));
   count = 0;
   FORALLvertices {
     if (++count % 100 == 0)
       qh_fprintf(qh, qh->ferr, 8112, "\n     ");
     qh_fprintf(qh, qh->ferr, 8113, " %d", vertex->id);
   }
   qh_fprintf(qh, qh->ferr, 8114, "\n");
 } /* printlists */
 
 /*---------------------------------
 
   qh_resetlists(qh, stats, qh_RESETvisible )
     reset newvertex_list, newfacet_list, visible_list
     if stats,
       maintains statistics
 
   returns:
     visible_list is empty if qh_deletevisible was called
 */
 void qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /*qh.newvertex_list newfacet_list visible_list*/) {
   vertexT *vertex;
   facetT *newfacet, *visible;
   int totnew=0, totver=0;
 
   if (stats) {
     FORALLvertex_(qh->newvertex_list)
       totver++;
     FORALLnew_facets
       totnew++;
     zadd_(Zvisvertextot, totver);
     zmax_(Zvisvertexmax, totver);
     zadd_(Znewfacettot, totnew);
     zmax_(Znewfacetmax, totnew);
   }
   FORALLvertex_(qh->newvertex_list)
     vertex->newlist= False;
   qh->newvertex_list= NULL;
   FORALLnew_facets
     newfacet->newfacet= False;
   qh->newfacet_list= NULL;
   if (resetVisible) {
     FORALLvisible_facets {
       visible->f.replace= NULL;
       visible->visible= False;
     }
     qh->num_visible= 0;
   }
   qh->visible_list= NULL; /* may still have visible facets via qh_triangulate */
   qh->NEWfacets= False;
 } /* resetlists */
 
 /*---------------------------------
 
   qh_setvoronoi_all(qh)
     compute Voronoi centers for all facets
     includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
 
   returns:
     facet->center is the Voronoi center
 
   notes:
     this is unused/untested code
       please email bradb@shore.net if this works ok for you
 
   use:
     FORALLvertices {...} to locate the vertex for a point.
     FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
 */
 void qh_setvoronoi_all(qhT *qh) {
   facetT *facet;
 
   qh_clearcenters(qh, qh_ASvoronoi);
   qh_vertexneighbors(qh);
 
   FORALLfacets {
     if (!facet->normal || !facet->upperdelaunay || qh->UPPERdelaunay) {
       if (!facet->center)
         facet->center= qh_facetcenter(qh, facet->vertices);
     }
   }
 } /* setvoronoi_all */
 
 #ifndef qh_NOmerge
 
 /*---------------------------------
 
   qh_triangulate()
     triangulate non-simplicial facets on qh.facet_list,
     if qh->VORONOI, sets Voronoi centers of non-simplicial facets
     nop if hasTriangulation
 
   returns:
     all facets simplicial
     each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
 
   notes:
     call after qh_check_output since may switch to Voronoi centers
     Output may overwrite ->f.triowner with ->f.area
 */
 void qh_triangulate(qhT *qh /*qh.facet_list*/) {
   facetT *facet, *nextfacet, *owner;
   int onlygood= qh->ONLYgood;
   facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;
   facetT *orig_neighbor= NULL, *otherfacet;
   vertexT *new_vertex_list= NULL;
   mergeT *merge;
   mergeType mergetype;
   int neighbor_i, neighbor_n;
 
   if (qh->hasTriangulation)
       return;
   trace1((qh, qh->ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));
   if (qh->hull_dim == 2)
     return;
   if (qh->VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
     qh_clearcenters(qh, qh_ASvoronoi);
     qh_vertexneighbors(qh);
   }
   qh->ONLYgood= False; /* for makenew_nonsimplicial */
   qh->visit_id++;
   qh->NEWfacets= True;
   qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);
   qh->newvertex_list= qh->vertex_tail;
   for (facet= qh->facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
     nextfacet= facet->next;
     if (facet->visible || facet->simplicial)
       continue;
     /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */
     if (!new_facet_list)
       new_facet_list= facet;  /* will be moved to end */
     qh_triangulate_facet(qh, facet, &new_vertex_list);
   }
   trace2((qh, qh->ferr, 2047, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));
   for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */
     nextfacet= facet->next;
     if (facet->visible)
       continue;
     if (facet->ridges) {
       if (qh_setsize(qh, facet->ridges) > 0) {
         qh_fprintf(qh, qh->ferr, 6161, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);
         qh_errexit(qh, qh_ERRqhull, facet, NULL);
       }
       qh_setfree(qh, &facet->ridges);
     }
     if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
       zinc_(Ztrinull);
       qh_triangulate_null(qh, facet);
     }
   }
   trace2((qh, qh->ferr, 2048, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh, qh->degen_mergeset)));
   qh->visible_list= qh->facet_tail;
   while ((merge= (mergeT*)qh_setdellast(qh->degen_mergeset))) {
     facet1= merge->facet1;
     facet2= merge->facet2;
     mergetype= merge->type;
     qh_memfree(qh, merge, (int)sizeof(mergeT));
     if (mergetype == MRGmirror) {
       zinc_(Ztrimirror);
       qh_triangulate_mirror(qh, facet1, facet2);
     }
   }
   qh_settempfree(qh, &qh->degen_mergeset);
   trace2((qh, qh->ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));
   qh->newvertex_list= new_vertex_list;  /* all vertices of new facets */
   qh->visible_list= NULL;
   qh_updatevertices(qh /*qh.newvertex_list, empty newfacet_list and visible_list*/);
   qh_resetlists(qh, False, !qh_RESETvisible /*qh.newvertex_list, empty newfacet_list and visible_list*/);
 
   trace2((qh, qh->ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));
   trace2((qh, qh->ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
   FORALLfacet_(new_facet_list) {
     if (facet->tricoplanar && !facet->visible) {
       FOREACHneighbor_i_(qh, facet) {
         if (neighbor_i == 0) {  /* first iteration */
           if (neighbor->tricoplanar)
             orig_neighbor= neighbor->f.triowner;
           else
             orig_neighbor= neighbor;
         }else {
           if (neighbor->tricoplanar)
             otherfacet= neighbor->f.triowner;
           else
             otherfacet= neighbor;
           if (orig_neighbor == otherfacet) {
             zinc_(Ztridegen);
             facet->degenerate= True;
             break;
           }
         }
       }
     }
   }
 
   trace2((qh, qh->ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
   owner= NULL;
   visible= NULL;
   for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */
     nextfacet= facet->next;
     if (facet->visible) {
       if (facet->tricoplanar) { /* a null or mirrored facet */
         qh_delfacet(qh, facet);
         qh->num_visible--;
       }else {  /* a non-simplicial facet followed by its tricoplanars */
         if (visible && !owner) {
           /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
           trace2((qh, qh->ferr, 2053, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",
                        visible->id));
           qh_delfacet(qh, visible);
           qh->num_visible--;
         }
         visible= facet;
         owner= NULL;
       }
     }else if (facet->tricoplanar) {
       if (facet->f.triowner != visible) {
         qh_fprintf(qh, qh->ferr, 6162, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
         qh_errexit2(qh, qh_ERRqhull, facet, visible);
       }
       if (owner)
         facet->f.triowner= owner;
       else if (!facet->degenerate) {
         owner= facet;
         nextfacet= visible->next; /* rescan tricoplanar facets with owner */
         facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
         facet->coplanarset= visible->coplanarset;
         facet->outsideset= visible->outsideset;
         visible->coplanarset= NULL;
         visible->outsideset= NULL;
         if (!qh->TRInormals) { /* center and normal copied to tricoplanar facets */
           visible->center= NULL;
           visible->normal= NULL;
         }
         qh_delfacet(qh, visible);
         qh->num_visible--;
       }
     }
   }
   if (visible && !owner) {
     trace2((qh, qh->ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
                  visible->id));
     qh_delfacet(qh, visible);
     qh->num_visible--;
   }
   qh->NEWfacets= False;
   qh->ONLYgood= onlygood; /* restore value */
   if (qh->CHECKfrequently)
     qh_checkpolygon(qh, qh->facet_list);
   qh->hasTriangulation= True;
 } /* triangulate */
 
 
 /*---------------------------------
 
   qh_triangulate_facet(qh, facetA)
     triangulate a non-simplicial facet
       if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
   returns:
     qh.newfacet_list == simplicial facets
       facet->tricoplanar set and ->keepcentrum false
       facet->degenerate set if duplicated apex
       facet->f.trivisible set to facetA
       facet->center copied from facetA (created if qh_ASvoronoi)
         qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
       facet->normal,offset,maxoutside copied from facetA
 
   notes:
       qh_makenew_nonsimplicial uses neighbor->seen for the same
 
   see also:
       qh_addpoint() -- add a point
       qh_makenewfacets() -- construct a cone of facets for a new vertex
 
   design:
       if qh_ASvoronoi,
          compute Voronoi center (facet->center)
       select first vertex (highest ID to preserve ID ordering of ->vertices)
       triangulate from vertex to ridges
       copy facet->center, normal, offset
       update vertex neighbors
 */
 void qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex) {
   facetT *newfacet;
   facetT *neighbor, **neighborp;
   vertexT *apex;
   int numnew=0;
 
   trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
 
   if (qh->IStracing >= 4)
     qh_printfacet(qh, qh->ferr, facetA);
   FOREACHneighbor_(facetA) {
     neighbor->seen= False;
     neighbor->coplanar= False;
   }
   if (qh->CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
         && fabs_(facetA->normal[qh->hull_dim -1]) >= qh->ANGLEround * qh_ZEROdelaunay) {
     facetA->center= qh_facetcenter(qh, facetA->vertices);
   }
   qh_willdelete(qh, facetA, NULL);
   qh->newfacet_list= qh->facet_tail;
   facetA->visitid= qh->visit_id;
   apex= SETfirstt_(facetA->vertices, vertexT);
   qh_makenew_nonsimplicial(qh, facetA, apex, &numnew);
   SETfirst_(facetA->neighbors)= NULL;
   FORALLnew_facets {
     newfacet->tricoplanar= True;
     newfacet->f.trivisible= facetA;
     newfacet->degenerate= False;
     newfacet->upperdelaunay= facetA->upperdelaunay;
     newfacet->good= facetA->good;
     if (qh->TRInormals) {
       newfacet->keepcentrum= True;
       newfacet->normal= qh_copypoints(qh, facetA->normal, 1, qh->hull_dim);
       if (qh->CENTERtype == qh_AScentrum)
         newfacet->center= qh_getcentrum(qh, newfacet);
       else
         newfacet->center= qh_copypoints(qh, facetA->center, 1, qh->hull_dim);
     }else {
       newfacet->keepcentrum= False;
       newfacet->normal= facetA->normal;
       newfacet->center= facetA->center;
     }
     newfacet->offset= facetA->offset;
 #if qh_MAXoutside
     newfacet->maxoutside= facetA->maxoutside;
 #endif
   }
   qh_matchnewfacets(qh /*qh.newfacet_list*/);
   zinc_(Ztricoplanar);
   zadd_(Ztricoplanartot, numnew);
   zmax_(Ztricoplanarmax, numnew);
   qh->visible_list= NULL;
   if (!(*first_vertex))
     (*first_vertex)= qh->newvertex_list;
   qh->newvertex_list= NULL;
   qh_updatevertices(qh /*qh.newfacet_list, empty visible_list and newvertex_list*/);
   qh_resetlists(qh, False, !qh_RESETvisible /*qh.newfacet_list, empty visible_list and newvertex_list*/);
 } /* triangulate_facet */
 
 /*---------------------------------
 
   qh_triangulate_link(qh, oldfacetA, facetA, oldfacetB, facetB)
     relink facetA to facetB via oldfacets
   returns:
     adds mirror facets to qh->degen_mergeset (4-d and up only)
   design:
     if they are already neighbors, the opposing neighbors become MRGmirror facets
 */
 void qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
   int errmirror= False;
 
   trace3((qh, qh->ferr, 3021, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n",
          oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));
   if (qh_setin(facetA->neighbors, facetB)) {
     if (!qh_setin(facetB->neighbors, facetA))
       errmirror= True;
     else
       qh_appendmergeset(qh, facetA, facetB, MRGmirror, NULL);
   }else if (qh_setin(facetB->neighbors, facetA))
     errmirror= True;
   if (errmirror) {
     qh_fprintf(qh, qh->ferr, 6163, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",
        facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
     qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
   }
   qh_setreplace(qh, facetB->neighbors, oldfacetB, facetA);
   qh_setreplace(qh, facetA->neighbors, oldfacetA, facetB);
 } /* triangulate_link */
 
 /*---------------------------------
 
   qh_triangulate_mirror(qh, facetA, facetB)
     delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror
       a mirrored facet shares the same vertices of a logical ridge
   design:
     since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
     if they are already neighbors, the opposing neighbors become MRGmirror facets
 */
 void qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB) {
   facetT *neighbor, *neighborB;
   int neighbor_i, neighbor_n;
 
   trace3((qh, qh->ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n",
          facetA->id, facetB->id));
   FOREACHneighbor_i_(qh, facetA) {
     neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
     if (neighbor == neighborB)
       continue; /* occurs twice */
     qh_triangulate_link(qh, facetA, neighbor, facetB, neighborB);
   }
   qh_willdelete(qh, facetA, NULL);
   qh_willdelete(qh, facetB, NULL);
 } /* triangulate_mirror */
 
 /*---------------------------------
 
   qh_triangulate_null(qh, facetA)
     remove null facetA from qh_triangulate_facet()
       a null facet has vertex #1 (apex) == vertex #2
   returns:
     adds facetA to ->visible for deletion after qh_updatevertices
     qh->degen_mergeset contains mirror facets (4-d and up only)
   design:
     since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
     if they are already neighbors, the opposing neighbors become MRGmirror facets
 */
 void qh_triangulate_null(qhT *qh, facetT *facetA) {
   facetT *neighbor, *otherfacet;
 
   trace3((qh, qh->ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
   neighbor= SETfirstt_(facetA->neighbors, facetT);
   otherfacet= SETsecondt_(facetA->neighbors, facetT);
   qh_triangulate_link(qh, facetA, neighbor, facetA, otherfacet);
   qh_willdelete(qh, facetA, NULL);
 } /* triangulate_null */
 
 #else /* qh_NOmerge */
 void qh_triangulate(qhT *qh) {
 }
 #endif /* qh_NOmerge */
 
    /*---------------------------------
 
   qh_vertexintersect(qh, vertexsetA, vertexsetB )
     intersects two vertex sets (inverse id ordered)
     vertexsetA is a temporary set at the top of qh->qhmem.tempstack
 
   returns:
     replaces vertexsetA with the intersection
 
   notes:
     could overwrite vertexsetA if currently too slow
 */
 void qh_vertexintersect(qhT *qh, setT **vertexsetA,setT *vertexsetB) {
   setT *intersection;
 
   intersection= qh_vertexintersect_new(qh, *vertexsetA, vertexsetB);
   qh_settempfree(qh, vertexsetA);
   *vertexsetA= intersection;
   qh_settemppush(qh, intersection);
 } /* vertexintersect */
 
 /*---------------------------------
 
   qh_vertexintersect_new(qh, )
     intersects two vertex sets (inverse id ordered)
 
   returns:
     a new set
 */
 setT *qh_vertexintersect_new(qhT *qh, setT *vertexsetA,setT *vertexsetB) {
   setT *intersection= qh_setnew(qh, qh->hull_dim - 1);
   vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
   vertexT **vertexB= SETaddr_(vertexsetB, vertexT);
 
   while (*vertexA && *vertexB) {
     if (*vertexA  == *vertexB) {
       qh_setappend(qh, &intersection, *vertexA);
       vertexA++; vertexB++;
     }else {
       if ((*vertexA)->id > (*vertexB)->id)
         vertexA++;
       else
         vertexB++;
     }
   }
   return intersection;
 } /* vertexintersect_new */
 
 /*---------------------------------
 
   qh_vertexneighbors(qh)
     for each vertex in qh.facet_list,
       determine its neighboring facets
 
   returns:
     sets qh.VERTEXneighbors
       nop if qh.VERTEXneighbors already set
       qh_addpoint() will maintain them
 
   notes:
     assumes all vertex->neighbors are NULL
 
   design:
     for each facet
       for each vertex
         append facet to vertex->neighbors
 */
 void qh_vertexneighbors(qhT *qh /*qh.facet_list*/) {
   facetT *facet;
   vertexT *vertex, **vertexp;
 
   if (qh->VERTEXneighbors)
     return;
   trace1((qh, qh->ferr, 1035, "qh_vertexneighbors: determing neighboring facets for each vertex\n"));
   qh->vertex_visit++;
   FORALLfacets {
     if (facet->visible)
       continue;
     FOREACHvertex_(facet->vertices) {
       if (vertex->visitid != qh->vertex_visit) {
         vertex->visitid= qh->vertex_visit;
         vertex->neighbors= qh_setnew(qh, qh->hull_dim);
       }
       qh_setappend(qh, &vertex->neighbors, facet);
     }
   }
   qh->VERTEXneighbors= True;
 } /* vertexneighbors */
 
 /*---------------------------------
 
   qh_vertexsubset(qh, vertexsetA, vertexsetB )
     returns True if vertexsetA is a subset of vertexsetB
     assumes vertexsets are sorted
 
   note:
     empty set is a subset of any other set
 */
 boolT qh_vertexsubset(qhT *qh, setT *vertexsetA, setT *vertexsetB) {
   vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
   vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
 
   while (True) {
     if (!*vertexA)
       return True;
     if (!*vertexB)
       return False;
     if ((*vertexA)->id > (*vertexB)->id)
       return False;
     if (*vertexA  == *vertexB)
       vertexA++;
     vertexB++;
   }
   return False; /* avoid warnings */
 } /* vertexsubset */
diff --git a/src/libqhullr/poly_r.c b/src/libqhullr/poly_r.c
index b1040fd..bb2cc36 100644
--- a/src/libqhullr/poly_r.c
+++ b/src/libqhullr/poly_r.c
@@ -1,1199 +1,1199 @@
 /*
  ---------------------------------
 
    poly_r.c
    implements polygons and simplices
 
    see qh-poly.htm, poly_r.h and libqhull_r.h
 
    infrequent code is in poly2_r.c
    (all but top 50 and their callers 12/3/95)
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/poly_r.c#7 $$Change: 1799 $
-   $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/poly_r.c#8 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_ra.h"
 
 /*======== functions in alphabetical order ==========*/
 
 /*---------------------------------
 
   qh_appendfacet(qh, facet )
     appends facet to end of qh.facet_list,
 
   returns:
     updates qh.newfacet_list, facet_next, facet_list
     increments qh.numfacets
 
   notes:
     assumes qh.facet_list/facet_tail is defined (createsimplex)
 
   see:
     qh_removefacet()
 
 */
 void qh_appendfacet(qhT *qh, facetT *facet) {
   facetT *tail= qh->facet_tail;
 
   if (tail == qh->newfacet_list)
     qh->newfacet_list= facet;
   if (tail == qh->facet_next)
     qh->facet_next= facet;
   facet->previous= tail->previous;
   facet->next= tail;
   if (tail->previous)
     tail->previous->next= facet;
   else
     qh->facet_list= facet;
   tail->previous= facet;
   qh->num_facets++;
   trace4((qh, qh->ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));
 } /* appendfacet */
 
 
 /*---------------------------------
 
   qh_appendvertex(qh, vertex )
     appends vertex to end of qh.vertex_list,
 
   returns:
     sets vertex->newlist
     updates qh.vertex_list, newvertex_list
     increments qh.num_vertices
 
   notes:
     assumes qh.vertex_list/vertex_tail is defined (createsimplex)
 
 */
 void qh_appendvertex(qhT *qh, vertexT *vertex) {
   vertexT *tail= qh->vertex_tail;
 
   if (tail == qh->newvertex_list)
     qh->newvertex_list= vertex;
   vertex->newlist= True;
   vertex->previous= tail->previous;
   vertex->next= tail;
   if (tail->previous)
     tail->previous->next= vertex;
   else
     qh->vertex_list= vertex;
   tail->previous= vertex;
   qh->num_vertices++;
   trace4((qh, qh->ferr, 4045, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));
 } /* appendvertex */
 
 
 /*---------------------------------
 
   qh_attachnewfacets(qh, )
     attach horizon facets to new facets in qh.newfacet_list
     newfacets have neighbor and ridge links to horizon but not vice versa
     only needed for qh.ONLYgood
 
   returns:
     set qh.NEWfacets
     horizon facets linked to new facets
       ridges changed from visible facets to new facets
       simplicial ridges deleted
     qh.visible_list, no ridges valid
     facet->f.replace is a newfacet (if any)
 
   design:
     delete interior ridges and neighbor sets by
       for each visible, non-simplicial facet
         for each ridge
           if last visit or if neighbor is simplicial
             if horizon neighbor
               delete ridge for horizon's ridge set
             delete ridge
         erase neighbor set
     attach horizon facets and new facets by
       for all new facets
         if corresponding horizon facet is simplicial
           locate corresponding visible facet {may be more than one}
           link visible facet to new facet
           replace visible facet with new facet in horizon
         else it's non-simplicial
           for all visible neighbors of the horizon facet
             link visible neighbor to new facet
             delete visible neighbor from horizon facet
           append new facet to horizon's neighbors
           the first ridge of the new facet is the horizon ridge
           link the new facet into the horizon ridge
 */
 void qh_attachnewfacets(qhT *qh /* qh.visible_list, newfacet_list */) {
   facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
   ridgeT *ridge, **ridgep;
 
   qh->NEWfacets= True;
   trace3((qh, qh->ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));
   qh->visit_id++;
   FORALLvisible_facets {
     visible->visitid= qh->visit_id;
     if (visible->ridges) {
       FOREACHridge_(visible->ridges) {
         neighbor= otherfacet_(ridge, visible);
         if (neighbor->visitid == qh->visit_id
             || (!neighbor->visible && neighbor->simplicial)) {
           if (!neighbor->visible)  /* delete ridge for simplicial horizon */
             qh_setdel(neighbor->ridges, ridge);
           qh_setfree(qh, &(ridge->vertices)); /* delete on 2nd visit */
           qh_memfree(qh, ridge, (int)sizeof(ridgeT));
         }
       }
       SETfirst_(visible->ridges)= NULL;
     }
     SETfirst_(visible->neighbors)= NULL;
   }
   trace1((qh, qh->ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));
   FORALLnew_facets {
     horizon= SETfirstt_(newfacet->neighbors, facetT);
     if (horizon->simplicial) {
       visible= NULL;
       FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
         if (neighbor->visible) {
           if (visible) {
             if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,
                                   SETindex_(horizon->neighbors, neighbor))) {
               visible= neighbor;
               break;
             }
           }else
             visible= neighbor;
         }
       }
       if (visible) {
         visible->f.replace= newfacet;
         qh_setreplace(qh, horizon->neighbors, visible, newfacet);
       }else {
         qh_fprintf(qh, qh->ferr, 6102, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n",
                  horizon->id, newfacet->id);
         qh_errexit2(qh, qh_ERRqhull, horizon, newfacet);
       }
     }else { /* non-simplicial, with a ridge for newfacet */
       FOREACHneighbor_(horizon) {    /* may hold for many new facets */
         if (neighbor->visible) {
           neighbor->f.replace= newfacet;
           qh_setdelnth(qh, horizon->neighbors,
                         SETindex_(horizon->neighbors, neighbor));
           neighborp--; /* repeat */
         }
       }
       qh_setappend(qh, &horizon->neighbors, newfacet);
       ridge= SETfirstt_(newfacet->ridges, ridgeT);
       if (ridge->top == horizon)
         ridge->bottom= newfacet;
       else
         ridge->top= newfacet;
       }
   } /* newfacets */
   if (qh->PRINTstatistics) {
     FORALLvisible_facets {
       if (!visible->f.replace)
         zinc_(Zinsidevisible);
     }
   }
 } /* attachnewfacets */
 
 /*---------------------------------
 
   qh_checkflipped(qh, facet, dist, allerror )
     checks facet orientation to interior point
 
     if allerror set,
       tests against qh.DISTround
     else
       tests against 0 since tested against DISTround before
 
   returns:
     False if it flipped orientation (sets facet->flipped)
     distance if non-NULL
 */
 boolT qh_checkflipped(qhT *qh, facetT *facet, realT *distp, boolT allerror) {
   realT dist;
 
   if (facet->flipped && !distp)
     return False;
   zzinc_(Zdistcheck);
   qh_distplane(qh, qh->interior_point, facet, &dist);
   if (distp)
     *distp= dist;
   if ((allerror && dist > -qh->DISTround)|| (!allerror && dist >= 0.0)) {
     facet->flipped= True;
     zzinc_(Zflippedfacets);
     trace0((qh, qh->ferr, 19, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n",
               facet->id, dist, qh->furthest_id));
     qh_precision(qh, "flipped facet");
     return False;
   }
   return True;
 } /* checkflipped */
 
 /*---------------------------------
 
   qh_delfacet(qh, facet )
     removes facet from facet_list and frees up its memory
 
   notes:
     assumes vertices and ridges already freed
 */
 void qh_delfacet(qhT *qh, facetT *facet) {
   void **freelistp; /* used !qh_NOmem */
 
   trace4((qh, qh->ferr, 4046, "qh_delfacet: delete f%d\n", facet->id));
   if (facet == qh->tracefacet)
     qh->tracefacet= NULL;
   if (facet == qh->GOODclosest)
     qh->GOODclosest= NULL;
   qh_removefacet(qh, facet);
   if (!facet->tricoplanar || facet->keepcentrum) {
     qh_memfree_(qh, facet->normal, qh->normal_size, freelistp);
     if (qh->CENTERtype == qh_ASvoronoi) {   /* uses macro calls */
       qh_memfree_(qh, facet->center, qh->center_size, freelistp);
     }else /* AScentrum */ {
       qh_memfree_(qh, facet->center, qh->normal_size, freelistp);
     }
   }
   qh_setfree(qh, &(facet->neighbors));
   if (facet->ridges)
     qh_setfree(qh, &(facet->ridges));
   qh_setfree(qh, &(facet->vertices));
   if (facet->outsideset)
     qh_setfree(qh, &(facet->outsideset));
   if (facet->coplanarset)
     qh_setfree(qh, &(facet->coplanarset));
   qh_memfree_(qh, facet, (int)sizeof(facetT), freelistp);
 } /* delfacet */
 
 
 /*---------------------------------
 
   qh_deletevisible()
     delete visible facets and vertices
 
   returns:
     deletes each facet and removes from facetlist
     at exit, qh.visible_list empty (== qh.newfacet_list)
 
   notes:
     ridges already deleted
     horizon facets do not reference facets on qh.visible_list
     new facets in qh.newfacet_list
     uses   qh.visit_id;
 */
 void qh_deletevisible(qhT *qh /*qh.visible_list*/) {
   facetT *visible, *nextfacet;
   vertexT *vertex, **vertexp;
   int numvisible= 0, numdel= qh_setsize(qh, qh->del_vertices);
 
   trace1((qh, qh->ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",
          qh->num_visible, numdel));
   for (visible= qh->visible_list; visible && visible->visible;
                 visible= nextfacet) { /* deleting current */
     nextfacet= visible->next;
     numvisible++;
     qh_delfacet(qh, visible);
   }
   if (numvisible != qh->num_visible) {
     qh_fprintf(qh, qh->ferr, 6103, "qhull internal error (qh_deletevisible): qh->num_visible %d is not number of visible facets %d\n",
              qh->num_visible, numvisible);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
   qh->num_visible= 0;
   zadd_(Zvisfacettot, numvisible);
   zmax_(Zvisfacetmax, numvisible);
   zzadd_(Zdelvertextot, numdel);
   zmax_(Zdelvertexmax, numdel);
   FOREACHvertex_(qh->del_vertices)
     qh_delvertex(qh, vertex);
   qh_settruncate(qh, qh->del_vertices, 0);
 } /* deletevisible */
 
 /*---------------------------------
 
   qh_facetintersect(qh, facetA, facetB, skipa, skipB, prepend )
     return vertices for intersection of two simplicial facets
     may include 1 prepended entry (if more, need to settemppush)
 
   returns:
     returns set of qh.hull_dim-1 + prepend vertices
     returns skipped index for each test and checks for exactly one
 
   notes:
     does not need settemp since set in quick memory
 
   see also:
     qh_vertexintersect and qh_vertexintersect_new
     use qh_setnew_delnthsorted to get nth ridge (no skip information)
 
   design:
     locate skipped vertex by scanning facet A's neighbors
     locate skipped vertex by scanning facet B's neighbors
     intersect the vertex sets
 */
 setT *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB,
                          int *skipA,int *skipB, int prepend) {
   setT *intersect;
   int dim= qh->hull_dim, i, j;
   facetT **neighborsA, **neighborsB;
 
   neighborsA= SETaddr_(facetA->neighbors, facetT);
   neighborsB= SETaddr_(facetB->neighbors, facetT);
   i= j= 0;
   if (facetB == *neighborsA++)
     *skipA= 0;
   else if (facetB == *neighborsA++)
     *skipA= 1;
   else if (facetB == *neighborsA++)
     *skipA= 2;
   else {
     for (i=3; i < dim; i++) {
       if (facetB == *neighborsA++) {
         *skipA= i;
         break;
       }
     }
   }
   if (facetA == *neighborsB++)
     *skipB= 0;
   else if (facetA == *neighborsB++)
     *skipB= 1;
   else if (facetA == *neighborsB++)
     *skipB= 2;
   else {
     for (j=3; j < dim; j++) {
       if (facetA == *neighborsB++) {
         *skipB= j;
         break;
       }
     }
   }
   if (i >= dim || j >= dim) {
     qh_fprintf(qh, qh->ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n",
             facetA->id, facetB->id);
     qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
   }
   intersect= qh_setnew_delnthsorted(qh, facetA->vertices, qh->hull_dim, *skipA, prepend);
   trace4((qh, qh->ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
           facetA->id, *skipA, facetB->id, *skipB));
   return(intersect);
 } /* facetintersect */
 
 /*---------------------------------
 
   qh_gethash(qh, hashsize, set, size, firstindex, skipelem )
     return hashvalue for a set with firstindex and skipelem
 
   notes:
     returned hash is in [0,hashsize)
     assumes at least firstindex+1 elements
     assumes skipelem is NULL, in set, or part of hash
 
     hashes memory addresses which may change over different runs of the same data
     using sum for hash does badly in high d
 */
 int qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem) {
   void **elemp= SETelemaddr_(set, firstindex, void);
   ptr_intT hash = 0, elem;
   unsigned result;
   int i;
 #ifdef _MSC_VER                   /* Microsoft Visual C++ -- warn about 64-bit issues */
 #pragma warning( push)            /* WARN64 -- ptr_intT holds a 64-bit pointer */
 #pragma warning( disable : 4311)  /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */
 #endif
 
   switch (size-firstindex) {
   case 1:
     hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
     break;
   case 2:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
     break;
   case 3:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       - (ptr_intT) skipelem;
     break;
   case 4:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
     break;
   case 5:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
     break;
   case 6:
     hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
       + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
       - (ptr_intT) skipelem;
     break;
   default:
     hash= 0;
     i= 3;
     do {     /* this is about 10% in 10-d */
       if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
         hash ^= (elem << i) + (elem >> (32-i));
         i += 3;
         if (i >= 32)
           i -= 32;
       }
     }while (*elemp);
     break;
   }
   if (hashsize<0) {
     qh_fprintf(qh, qh->ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly.c]\n", hashsize);
     qh_errexit2(qh, qh_ERRqhull, NULL, NULL);
   }
   result= (unsigned)hash;
   result %= (unsigned)hashsize;
   /* result= 0; for debugging */
   return result;
 #ifdef _MSC_VER
 #pragma warning( pop)
 #endif
 } /* gethash */
 
 /*---------------------------------
 
   qh_makenewfacet(qh, vertices, toporient, horizon )
     creates a toporient? facet from vertices
 
   returns:
     returns newfacet
       adds newfacet to qh.facet_list
       newfacet->vertices= vertices
       if horizon
         newfacet->neighbor= horizon, but not vice versa
     newvertex_list updated with vertices
 */
 facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient,facetT *horizon) {
   facetT *newfacet;
   vertexT *vertex, **vertexp;
 
   FOREACHvertex_(vertices) {
     if (!vertex->newlist) {
       qh_removevertex(qh, vertex);
       qh_appendvertex(qh, vertex);
     }
   }
   newfacet= qh_newfacet(qh);
   newfacet->vertices= vertices;
   newfacet->toporient= (unsigned char)toporient;
   if (horizon)
     qh_setappend(qh, &(newfacet->neighbors), horizon);
   qh_appendfacet(qh, newfacet);
   return(newfacet);
 } /* makenewfacet */
 
 
 /*---------------------------------
 
   qh_makenewplanes()
     make new hyperplanes for facets on qh.newfacet_list
 
   returns:
     all facets have hyperplanes or are marked for   merging
     doesn't create hyperplane if horizon is coplanar (will merge)
     updates qh.min_vertex if qh.JOGGLEmax
 
   notes:
     facet->f.samecycle is defined for facet->mergehorizon facets
 */
 void qh_makenewplanes(qhT *qh /* qh.newfacet_list */) {
   facetT *newfacet;
 
   FORALLnew_facets {
     if (!newfacet->mergehorizon)
       qh_setfacetplane(qh, newfacet);
   }
   if (qh->JOGGLEmax < REALmax/2)
     minimize_(qh->min_vertex, -wwval_(Wnewvertexmax));
 } /* makenewplanes */
 
 /*---------------------------------
 
   qh_makenew_nonsimplicial(qh, visible, apex, numnew )
     make new facets for ridges of a visible facet
 
   returns:
     first newfacet, bumps numnew as needed
     attaches new facets if !qh.ONLYgood
     marks ridge neighbors for simplicial visible
     if (qh.ONLYgood)
       ridges on newfacet, horizon, and visible
     else
       ridge and neighbors between newfacet and   horizon
       visible facet's ridges are deleted
 
   notes:
     qh.visit_id if visible has already been processed
     sets neighbor->seen for building f.samecycle
       assumes all 'seen' flags initially false
 
   design:
     for each ridge of visible facet
       get neighbor of visible facet
       if neighbor was already processed
         delete the ridge (will delete all visible facets later)
       if neighbor is a horizon facet
         create a new facet
         if neighbor coplanar
           adds newfacet to f.samecycle for later merging
         else
           updates neighbor's neighbor set
           (checks for non-simplicial facet with multiple ridges to visible facet)
         updates neighbor's ridge set
         (checks for simplicial neighbor to non-simplicial visible facet)
         (deletes ridge if neighbor is simplicial)
 
 */
 #ifndef qh_NOmerge
 facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
   void **freelistp; /* used !qh_NOmem */
   ridgeT *ridge, **ridgep;
   facetT *neighbor, *newfacet= NULL, *samecycle;
   setT *vertices;
   boolT toporient;
   int ridgeid;
 
   FOREACHridge_(visible->ridges) {
     ridgeid= ridge->id;
     neighbor= otherfacet_(ridge, visible);
     if (neighbor->visible) {
       if (!qh->ONLYgood) {
         if (neighbor->visitid == qh->visit_id) {
           qh_setfree(qh, &(ridge->vertices));  /* delete on 2nd visit */
           qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
         }
       }
     }else {  /* neighbor is an horizon facet */
       toporient= (ridge->top == visible);
       vertices= qh_setnew(qh, qh->hull_dim); /* makes sure this is quick */
       qh_setappend(qh, &vertices, apex);
       qh_setappend_set(qh, &vertices, ridge->vertices);
       newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);
       (*numnew)++;
       if (neighbor->coplanar) {
         newfacet->mergehorizon= True;
         if (!neighbor->seen) {
           newfacet->f.samecycle= newfacet;
           neighbor->f.newcycle= newfacet;
         }else {
           samecycle= neighbor->f.newcycle;
           newfacet->f.samecycle= samecycle->f.samecycle;
           samecycle->f.samecycle= newfacet;
         }
       }
       if (qh->ONLYgood) {
         if (!neighbor->simplicial)
           qh_setappend(qh, &(newfacet->ridges), ridge);
       }else {  /* qh_attachnewfacets */
         if (neighbor->seen) {
           if (neighbor->simplicial) {
             qh_fprintf(qh, qh->ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",
                    neighbor->id, visible->id);
             qh_errexit2(qh, qh_ERRqhull, neighbor, visible);
           }
           qh_setappend(qh, &(neighbor->neighbors), newfacet);
         }else
           qh_setreplace(qh, neighbor->neighbors, visible, newfacet);
         if (neighbor->simplicial) {
           qh_setdel(neighbor->ridges, ridge);
           qh_setfree(qh, &(ridge->vertices));
           qh_memfree(qh, ridge, (int)sizeof(ridgeT));
         }else {
           qh_setappend(qh, &(newfacet->ridges), ridge);
           if (toporient)
             ridge->top= newfacet;
           else
             ridge->bottom= newfacet;
         }
       trace4((qh, qh->ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
             newfacet->id, apex->id, ridgeid, neighbor->id));
       }
     }
     neighbor->seen= True;
   } /* for each ridge */
   if (!qh->ONLYgood)
     SETfirst_(visible->ridges)= NULL;
   return newfacet;
 } /* makenew_nonsimplicial */
 #else /* qh_NOmerge */
 facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
   return NULL;
 }
 #endif /* qh_NOmerge */
 
 /*---------------------------------
 
   qh_makenew_simplicial(qh, visible, apex, numnew )
     make new facets for simplicial visible facet and apex
 
   returns:
     attaches new facets if (!qh.ONLYgood)
       neighbors between newfacet and horizon
 
   notes:
     nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial)
 
   design:
     locate neighboring horizon facet for visible facet
     determine vertices and orientation
     create new facet
     if coplanar,
       add new facet to f.samecycle
     update horizon facet's neighbor list
 */
 facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
   facetT *neighbor, **neighborp, *newfacet= NULL;
   setT *vertices;
   boolT flip, toporient;
   int horizonskip, visibleskip;
 
   FOREACHneighbor_(visible) {
     if (!neighbor->seen && !neighbor->visible) {
       vertices= qh_facetintersect(qh, neighbor,visible, &horizonskip, &visibleskip, 1);
       SETfirst_(vertices)= apex;
       flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));
       if (neighbor->toporient)
         toporient= horizonskip & 0x1;
       else
         toporient= (horizonskip & 0x1) ^ 0x1;
       newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);
       (*numnew)++;
       if (neighbor->coplanar && (qh->PREmerge || qh->MERGEexact)) {
 #ifndef qh_NOmerge
         newfacet->f.samecycle= newfacet;
         newfacet->mergehorizon= True;
 #endif
       }
       if (!qh->ONLYgood)
         SETelem_(neighbor->neighbors, horizonskip)= newfacet;
       trace4((qh, qh->ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
             newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
               neighbor->toporient, visible->id, visibleskip, flip));
     }
   }
   return newfacet;
 } /* makenew_simplicial */
 
 /*---------------------------------
 
   qh_matchneighbor(qh, newfacet, newskip, hashsize, hashcount )
     either match subridge of newfacet with neighbor or add to hash_table
 
   returns:
     duplicate ridges are unmatched and marked by qh_DUPLICATEridge
 
   notes:
     ridge is newfacet->vertices w/o newskip vertex
     do not allocate memory (need to free hash_table cleanly)
     uses linear hash chains
 
   see also:
     qh_matchduplicates
 
   design:
     for each possible matching facet in qh.hash_table
       if vertices match
         set ismatch, if facets have opposite orientation
         if ismatch and matching facet doesn't have a match
           match the facets by updating their neighbor sets
         else
           indicate a duplicate ridge
           set facet hyperplane for later testing
           add facet to hashtable
           unless the other facet was already a duplicate ridge
             mark both facets with a duplicate ridge
             add other facet (if defined) to hash table
 */
 void qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize, int *hashcount) {
   boolT newfound= False;   /* True, if new facet is already in hash chain */
   boolT same, ismatch;
   int hash, scan;
   facetT *facet, *matchfacet;
   int skip, matchskip;
 
   hash= qh_gethash(qh, hashsize, newfacet->vertices, qh->hull_dim, 1,
                      SETelem_(newfacet->vertices, newskip));
   trace4((qh, qh->ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
           newfacet->id, newskip, hash, *hashcount));
   zinc_(Zhashlookup);
   for (scan= hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
        scan= (++scan >= hashsize ? 0 : scan)) {
     if (facet == newfacet) {
       newfound= True;
       continue;
     }
     zinc_(Zhashtests);
     if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
       if (SETelem_(newfacet->vertices, newskip) ==
           SETelem_(facet->vertices, skip)) {
         qh_precision(qh, "two facets with the same vertices");
         qh_fprintf(qh, qh->ferr, 6106, "qhull precision error: Vertex sets are the same for f%d and f%d.  Can not force output.\n",
           facet->id, newfacet->id);
         qh_errexit2(qh, qh_ERRprec, facet, newfacet);
       }
       ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));
       matchfacet= SETelemt_(facet->neighbors, skip, facetT);
       if (ismatch && !matchfacet) {
         SETelem_(facet->neighbors, skip)= newfacet;
         SETelem_(newfacet->neighbors, newskip)= facet;
         (*hashcount)--;
         trace4((qh, qh->ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
            facet->id, skip, newfacet->id, newskip));
         return;
       }
       if (!qh->PREmerge && !qh->MERGEexact) {
         qh_precision(qh, "a ridge with more than two neighbors");
         qh_fprintf(qh, qh->ferr, 6107, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue.\n",
                  facet->id, newfacet->id, getid_(matchfacet));
         qh_errexit2(qh, qh_ERRprec, facet, newfacet);
       }
       SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
       newfacet->dupridge= True;
       if (!newfacet->normal)
         qh_setfacetplane(qh, newfacet);
       qh_addhash(qh, newfacet, qh->hash_table, hashsize, hash);
       (*hashcount)++;
       if (!facet->normal)
         qh_setfacetplane(qh, facet);
       if (matchfacet != qh_DUPLICATEridge) {
         SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
         facet->dupridge= True;
         if (!facet->normal)
           qh_setfacetplane(qh, facet);
         if (matchfacet) {
           matchskip= qh_setindex(matchfacet->neighbors, facet);
           SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge;
           matchfacet->dupridge= True;
           if (!matchfacet->normal)
             qh_setfacetplane(qh, matchfacet);
           qh_addhash(qh, matchfacet, qh->hash_table, hashsize, hash);
           *hashcount += 2;
         }
       }
       trace4((qh, qh->ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
            newfacet->id, newskip, facet->id, skip,
            (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),
            ismatch, hash));
       return; /* end of duplicate ridge */
     }
   }
   if (!newfound)
     SETelem_(qh->hash_table, scan)= newfacet;  /* same as qh_addhash */
   (*hashcount)++;
   trace4((qh, qh->ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
            newfacet->id, newskip, hash));
 } /* matchneighbor */
 
 
 /*---------------------------------
 
   qh_matchnewfacets()
     match newfacets in qh.newfacet_list to their newfacet neighbors
 
   returns:
     qh.newfacet_list with full neighbor sets
       get vertices with nth neighbor by deleting nth vertex
     if qh.PREmerge/MERGEexact or qh.FORCEoutput
       sets facet->flippped if flipped normal (also prevents point partitioning)
     if duplicate ridges and qh.PREmerge/MERGEexact
       sets facet->dupridge
       missing neighbor links identifies extra ridges to be merging (qh_MERGEridge)
 
   notes:
     newfacets already have neighbor[0] (horizon facet)
     assumes qh.hash_table is NULL
     vertex->neighbors has not been updated yet
     do not allocate memory after qh.hash_table (need to free it cleanly)
 
   design:
     delete neighbor sets for all new facets
     initialize a hash table
     for all new facets
       match facet with neighbors
     if unmatched facets (due to duplicate ridges)
       for each new facet with a duplicate ridge
         match it with a facet
     check for flipped facets
 */
 void qh_matchnewfacets(qhT *qh /* qh.newfacet_list */) {
   int numnew=0, hashcount=0, newskip;
   facetT *newfacet, *neighbor;
   int dim= qh->hull_dim, hashsize, neighbor_i, neighbor_n;
   setT *neighbors;
 #ifndef qh_NOtrace
   int facet_i, facet_n, numfree= 0;
   facetT *facet;
 #endif
 
   trace1((qh, qh->ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));
   FORALLnew_facets {
     numnew++;
     {  /* inline qh_setzero(qh, newfacet->neighbors, 1, qh->hull_dim); */
       neighbors= newfacet->neighbors;
       neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
       memset((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize);
     }
   }
 
   qh_newhashtable(qh, numnew*(qh->hull_dim-1)); /* twice what is normally needed,
                                      but every ridge could be DUPLICATEridge */
   hashsize= qh_setsize(qh, qh->hash_table);
   FORALLnew_facets {
     for (newskip=1; newskiphull_dim; newskip++) /* furthest/horizon already matched */
       qh_matchneighbor(qh, newfacet, newskip, hashsize, &hashcount);
 #if 0   /* use the following to trap hashcount errors */
     {
       int count= 0, k;
       facetT *facet, *neighbor;
 
       count= 0;
       FORALLfacet_(qh->newfacet_list) {  /* newfacet already in use */
         for (k=1; k < qh->hull_dim; k++) {
           neighbor= SETelemt_(facet->neighbors, k, facetT);
           if (!neighbor || neighbor == qh_DUPLICATEridge)
             count++;
         }
         if (facet == newfacet)
           break;
       }
       if (count != hashcount) {
         qh_fprintf(qh, qh->ferr, 8088, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n",
                  newfacet->id, hashcount, count);
         qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
       }
     }
 #endif  /* end of trap code */
   }
   if (hashcount) {
     FORALLnew_facets {
       if (newfacet->dupridge) {
         FOREACHneighbor_i_(qh, newfacet) {
           if (neighbor == qh_DUPLICATEridge) {
             qh_matchduplicates(qh, newfacet, neighbor_i, hashsize, &hashcount);
                     /* this may report MERGEfacet */
           }
         }
       }
     }
   }
   if (hashcount) {
     qh_fprintf(qh, qh->ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
         hashcount);
     qh_printhashtable(qh, qh->ferr);
     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
   }
 #ifndef qh_NOtrace
   if (qh->IStracing >= 2) {
     FOREACHfacet_i_(qh, qh->hash_table) {
       if (!facet)
         numfree++;
     }
     qh_fprintf(qh, qh->ferr, 8089, "qh_matchnewfacets: %d new facets, %d unused hash entries .  hashsize %d\n",
              numnew, numfree, qh_setsize(qh, qh->hash_table));
   }
 #endif /* !qh_NOtrace */
   qh_setfree(qh, &qh->hash_table);
   if (qh->PREmerge || qh->MERGEexact) {
     if (qh->IStracing >= 4)
       qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
     FORALLnew_facets {
       if (newfacet->normal)
         qh_checkflipped(qh, newfacet, NULL, qh_ALL);
     }
   }else if (qh->FORCEoutput)
     qh_checkflipped_all(qh, qh->newfacet_list);  /* prints warnings for flipped */
 } /* matchnewfacets */
 
 
 /*---------------------------------
 
   qh_matchvertices(qh, firstindex, verticesA, skipA, verticesB, skipB, same )
     tests whether vertices match with a single skip
     starts match at firstindex since all new facets have a common vertex
 
   returns:
     true if matched vertices
     skip index for each set
     sets same iff vertices have the same orientation
 
   notes:
     assumes skipA is in A and both sets are the same size
 
   design:
     set up pointers
     scan both sets checking for a match
     test orientation
 */
 boolT qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,
        setT *verticesB, int *skipB, boolT *same) {
   vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;
 
   elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
   elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
   skipAp= SETelemaddr_(verticesA, skipA, vertexT);
   do if (elemAp != skipAp) {
     while (*elemAp != *elemBp++) {
       if (skipBp)
         return False;
       skipBp= elemBp;  /* one extra like FOREACH */
     }
   }while (*(++elemAp));
   if (!skipBp)
     skipBp= ++elemBp;
   *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB */
   *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */
   trace4((qh, qh->ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",
           skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
   return(True);
 } /* matchvertices */
 
 /*---------------------------------
 
   qh_newfacet(qh)
     return a new facet
 
   returns:
     all fields initialized or cleared   (NULL)
     preallocates neighbors set
 */
 facetT *qh_newfacet(qhT *qh) {
   facetT *facet;
   void **freelistp; /* used !qh_NOmem */
 
   qh_memalloc_(qh, (int)sizeof(facetT), freelistp, facet, facetT);
   memset((char *)facet, (size_t)0, sizeof(facetT));
   if (qh->facet_id == qh->tracefacet_id)
     qh->tracefacet= facet;
   facet->id= qh->facet_id++;
   facet->neighbors= qh_setnew(qh, qh->hull_dim);
 #if !qh_COMPUTEfurthest
   facet->furthestdist= 0.0;
 #endif
 #if qh_MAXoutside
   if (qh->FORCEoutput && qh->APPROXhull)
     facet->maxoutside= qh->MINoutside;
   else
     facet->maxoutside= qh->DISTround;
 #endif
   facet->simplicial= True;
   facet->good= True;
   facet->newfacet= True;
   trace4((qh, qh->ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));
   return(facet);
 } /* newfacet */
 
 
 /*---------------------------------
 
   qh_newridge()
     return a new ridge
 */
 ridgeT *qh_newridge(qhT *qh) {
   ridgeT *ridge;
   void **freelistp;   /* used !qh_NOmem */
 
   qh_memalloc_(qh, (int)sizeof(ridgeT), freelistp, ridge, ridgeT);
   memset((char *)ridge, (size_t)0, sizeof(ridgeT));
   zinc_(Ztotridges);
   if (qh->ridge_id == 0xFFFFFF) {
     qh_fprintf(qh, qh->ferr, 7074, "\
 qhull warning: more than %d ridges.  ID field overflows and two ridges\n\
 may have the same identifier.  Otherwise output ok.\n", 0xFFFFFF);
   }
   ridge->id= qh->ridge_id++;
   trace4((qh, qh->ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));
   return(ridge);
 } /* newridge */
 
 
 /*---------------------------------
 
   qh_pointid(qh, )
     return id for a point,
     returns -3 if null, -2 if interior, or -1 if not known
 
   alternative code:
     unsigned long id;
     id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;
 
   notes:
     WARN64 -- id truncated to 32-bits, at most 2G points
     NOerrors returned (QhullPoint::id)
     if point not in point array
       the code does a comparison of unrelated pointers.
 */
 int qh_pointid(qhT *qh, pointT *point) {
   ptr_intT offset, id;
 
   if (!point || !qh)
     return -3;
   else if (point == qh->interior_point)
     return -2;
   else if (point >= qh->first_point
   && point < qh->first_point + qh->num_points * qh->hull_dim) {
     offset= (ptr_intT)(point - qh->first_point);
     id= offset / qh->hull_dim;
   }else if ((id= qh_setindex(qh->other_points, point)) != -1)
     id += qh->num_points;
   else
     return -1;
   return (int)id;
 } /* pointid */
 
 /*---------------------------------
 
   qh_removefacet(qh, facet )
     unlinks facet from qh.facet_list,
 
   returns:
     updates qh.facet_list .newfacet_list .facet_next visible_list
     decrements qh.num_facets
 
   see:
     qh_appendfacet
 */
 void qh_removefacet(qhT *qh, facetT *facet) {
   facetT *next= facet->next, *previous= facet->previous;
 
   if (facet == qh->newfacet_list)
     qh->newfacet_list= next;
   if (facet == qh->facet_next)
     qh->facet_next= next;
   if (facet == qh->visible_list)
     qh->visible_list= next;
   if (previous) {
     previous->next= next;
     next->previous= previous;
   }else {  /* 1st facet in qh->facet_list */
     qh->facet_list= next;
     qh->facet_list->previous= NULL;
   }
   qh->num_facets--;
   trace4((qh, qh->ferr, 4057, "qh_removefacet: remove f%d from facet_list\n", facet->id));
 } /* removefacet */
 
 
 /*---------------------------------
 
   qh_removevertex(qh, vertex )
     unlinks vertex from qh.vertex_list,
 
   returns:
     updates qh.vertex_list .newvertex_list
     decrements qh.num_vertices
 */
 void qh_removevertex(qhT *qh, vertexT *vertex) {
   vertexT *next= vertex->next, *previous= vertex->previous;
 
   if (vertex == qh->newvertex_list)
     qh->newvertex_list= next;
   if (previous) {
     previous->next= next;
     next->previous= previous;
   }else {  /* 1st vertex in qh->vertex_list */
     qh->vertex_list= vertex->next;
     qh->vertex_list->previous= NULL;
   }
   qh->num_vertices--;
   trace4((qh, qh->ferr, 4058, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));
 } /* removevertex */
 
 
 /*---------------------------------
 
   qh_updatevertices()
     update vertex neighbors and delete interior vertices
 
   returns:
     if qh.VERTEXneighbors, updates neighbors for each vertex
       if qh.newvertex_list,
          removes visible neighbors  from vertex neighbors
       if qh.newfacet_list
          adds new facets to vertex neighbors
     if qh.visible_list
        interior vertices added to qh.del_vertices for later partitioning
 
   design:
     if qh.VERTEXneighbors
       deletes references to visible facets from vertex neighbors
       appends new facets to the neighbor list for each vertex
       checks all vertices of visible facets
         removes visible facets from neighbor lists
         marks unused vertices for deletion
 */
 void qh_updatevertices(qhT *qh /*qh.newvertex_list, newfacet_list, visible_list*/) {
   facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
   vertexT *vertex, **vertexp;
 
   trace3((qh, qh->ferr, 3013, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n"));
   if (qh->VERTEXneighbors) {
     FORALLvertex_(qh->newvertex_list) {
       FOREACHneighbor_(vertex) {
         if (neighbor->visible)
           SETref_(neighbor)= NULL;
       }
       qh_setcompact(qh, vertex->neighbors);
     }
     FORALLnew_facets {
       FOREACHvertex_(newfacet->vertices)
         qh_setappend(qh, &vertex->neighbors, newfacet);
     }
     FORALLvisible_facets {
       FOREACHvertex_(visible->vertices) {
         if (!vertex->newlist && !vertex->deleted) {
           FOREACHneighbor_(vertex) { /* this can happen under merging */
             if (!neighbor->visible)
               break;
           }
           if (neighbor)
             qh_setdel(vertex->neighbors, visible);
           else {
             vertex->deleted= True;
             qh_setappend(qh, &qh->del_vertices, vertex);
             trace2((qh, qh->ferr, 2041, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",
                   qh_pointid(qh, vertex->point), vertex->id, visible->id));
           }
         }
       }
     }
   }else {  /* !VERTEXneighbors */
     FORALLvisible_facets {
       FOREACHvertex_(visible->vertices) {
         if (!vertex->newlist && !vertex->deleted) {
           vertex->deleted= True;
           qh_setappend(qh, &qh->del_vertices, vertex);
           trace2((qh, qh->ferr, 2042, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",
                   qh_pointid(qh, vertex->point), vertex->id, visible->id));
         }
       }
     }
   }
 } /* updatevertices */
 
 
 
diff --git a/src/libqhullr/poly_r.h b/src/libqhullr/poly_r.h
index dc27d33..3ab3b4e 100644
--- a/src/libqhullr/poly_r.h
+++ b/src/libqhullr/poly_r.h
@@ -1,295 +1,295 @@
 /*
  ---------------------------------
 
    poly_r.h
    header file for poly_r.c and poly2_r.c
 
    see qh-poly.htm, libqhull_r.h and poly_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/poly_r.h#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/poly_r.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFpoly
 #define qhDEFpoly 1
 
 #include "libqhull_r.h"
 
 /*===============   constants ========================== */
 
 /*----------------------------------
 
   ALGORITHMfault
     use as argument to checkconvex() to report errors during buildhull
 */
 #define qh_ALGORITHMfault 0
 
 /*----------------------------------
 
   DATAfault
     use as argument to checkconvex() to report errors during initialhull
 */
 #define qh_DATAfault 1
 
 /*----------------------------------
 
   DUPLICATEridge
     special value for facet->neighbor to indicate a duplicate ridge
 
   notes:
     set by matchneighbor, used by matchmatch and mark_dupridge
 */
 #define qh_DUPLICATEridge (facetT *)1L
 
 /*----------------------------------
 
   MERGEridge       flag in facet
     special value for facet->neighbor to indicate a merged ridge
 
   notes:
     set by matchneighbor, used by matchmatch and mark_dupridge
 */
 #define qh_MERGEridge (facetT *)2L
 
 
 /*============ -structures- ====================*/
 
 /*=========== -macros- =========================*/
 
 /*----------------------------------
 
   FORALLfacet_( facetlist ) { ... }
     assign 'facet' to each facet in facetlist
 
   notes:
     uses 'facetT *facet;'
     assumes last facet is a sentinel
 
   see:
     FORALLfacets
 */
 #define FORALLfacet_( facetlist ) if (facetlist ) for ( facet=( facetlist ); facet && facet->next; facet= facet->next )
 
 /*----------------------------------
 
   FORALLnew_facets { ... }
     assign 'newfacet' to each facet in qh.newfacet_list
 
   notes:
     uses 'facetT *newfacet;'
     at exit, newfacet==NULL
 */
 #define FORALLnew_facets for ( newfacet=qh->newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
 
 /*----------------------------------
 
   FORALLvertex_( vertexlist ) { ... }
     assign 'vertex' to each vertex in vertexlist
 
   notes:
     uses 'vertexT *vertex;'
     at exit, vertex==NULL
 */
 #define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
 
 /*----------------------------------
 
   FORALLvisible_facets { ... }
     assign 'visible' to each visible facet in qh.visible_list
 
   notes:
     uses 'vacetT *visible;'
     at exit, visible==NULL
 */
 #define FORALLvisible_facets for (visible=qh->visible_list; visible && visible->visible; visible= visible->next)
 
 /*----------------------------------
 
   FORALLsame_( newfacet ) { ... }
     assign 'same' to each facet in newfacet->f.samecycle
 
   notes:
     uses 'facetT *same;'
     stops when it returns to newfacet
 */
 #define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
 
 /*----------------------------------
 
   FORALLsame_cycle_( newfacet ) { ... }
     assign 'same' to each facet in newfacet->f.samecycle
 
   notes:
     uses 'facetT *same;'
     at exit, same == NULL
 */
 #define FORALLsame_cycle_(newfacet) \
      for (same= newfacet->f.samecycle; \
          same; same= (same == newfacet ?  NULL : same->f.samecycle))
 
 /*----------------------------------
 
   FOREACHneighborA_( facet ) { ... }
     assign 'neighborA' to each neighbor in facet->neighbors
 
   FOREACHneighborA_( vertex ) { ... }
     assign 'neighborA' to each neighbor in vertex->neighbors
 
   declare:
     facetT *neighborA, **neighborAp;
 
   see:
     FOREACHsetelement_
 */
 #define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
 
 /*----------------------------------
 
   FOREACHvisible_( facets ) { ... }
     assign 'visible' to each facet in facets
 
   notes:
     uses 'facetT *facet, *facetp;'
     see FOREACHsetelement_
 */
 #define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
 
 /*----------------------------------
 
   FOREACHnewfacet_( facets ) { ... }
     assign 'newfacet' to each facet in facets
 
   notes:
     uses 'facetT *newfacet, *newfacetp;'
     see FOREACHsetelement_
 */
 #define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
 
 /*----------------------------------
 
   FOREACHvertexA_( vertices ) { ... }
     assign 'vertexA' to each vertex in vertices
 
   notes:
     uses 'vertexT *vertexA, *vertexAp;'
     see FOREACHsetelement_
 */
 #define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
 
 /*----------------------------------
 
   FOREACHvertexreverse12_( vertices ) { ... }
     assign 'vertex' to each vertex in vertices
     reverse order of first two vertices
 
   notes:
     uses 'vertexT *vertex, *vertexp;'
     see FOREACHsetelement_
 */
 #define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
 
 
 /*=============== prototypes poly_r.c in alphabetical order ================*/
 
 void    qh_appendfacet(qhT *qh, facetT *facet);
 void    qh_appendvertex(qhT *qh, vertexT *vertex);
 void    qh_attachnewfacets(qhT *qh /* qh.visible_list, newfacet_list */);
 boolT   qh_checkflipped(qhT *qh, facetT *facet, realT *dist, boolT allerror);
 void    qh_delfacet(qhT *qh, facetT *facet);
 void    qh_deletevisible(qhT *qh /* qh.visible_list, qh.horizon_list */);
 setT   *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
 int     qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem);
 facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient, facetT *facet);
 void    qh_makenewplanes(qhT *qh /* qh.newfacet_list */);
 facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew);
 facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew);
 void    qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize,
                           int *hashcount);
 void    qh_matchnewfacets(qhT *qh);
 boolT   qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,
                           setT *verticesB, int *skipB, boolT *same);
 facetT *qh_newfacet(qhT *qh);
 ridgeT *qh_newridge(qhT *qh);
 int     qh_pointid(qhT *qh, pointT *point);
 void    qh_removefacet(qhT *qh, facetT *facet);
 void    qh_removevertex(qhT *qh, vertexT *vertex);
 void    qh_updatevertices(qhT *qh);
 
 
 /*========== -prototypes poly2_r.c in alphabetical order ===========*/
 
 void    qh_addhash(qhT *qh, void *newelem, setT *hashtable, int hashsize, int hash);
 void    qh_check_bestdist(qhT *qh);
 void    qh_check_maxout(qhT *qh);
 void    qh_check_output(qhT *qh);
 void    qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
 void    qh_check_points(qhT *qh);
 void    qh_checkconvex(qhT *qh, facetT *facetlist, int fault);
 void    qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp);
 void    qh_checkflipped_all(qhT *qh, facetT *facetlist);
 void    qh_checkpolygon(qhT *qh, facetT *facetlist);
 void    qh_checkvertex(qhT *qh, vertexT *vertex);
 void    qh_clearcenters(qhT *qh, qh_CENTER type);
 void    qh_createsimplex(qhT *qh, setT *vertices);
 void    qh_delridge(qhT *qh, ridgeT *ridge);
 void    qh_delvertex(qhT *qh, vertexT *vertex);
 setT   *qh_facet3vertex(qhT *qh, facetT *facet);
 facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
            realT *bestdist, boolT *isoutside);
 facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart);
 facetT *qh_findfacet_all(qhT *qh, pointT *point, realT *bestdist, boolT *isoutside,
                           int *numpart);
 int     qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon);
 void    qh_findgood_all(qhT *qh, facetT *facetlist);
 void    qh_furthestnext(qhT *qh /* qh.facet_list */);
 void    qh_furthestout(qhT *qh, facetT *facet);
 void    qh_infiniteloop(qhT *qh, facetT *facet);
 void    qh_initbuild(qhT *qh);
 void    qh_initialhull(qhT *qh, setT *vertices);
 setT   *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints);
 vertexT *qh_isvertex(qhT *qh, pointT *point, setT *vertices);
 vertexT *qh_makenewfacets(qhT *qh, pointT *point /*horizon_list, visible_list*/);
 void    qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount);
 void    qh_nearcoplanar(qhT *qh /* qh.facet_list */);
 vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp);
 int     qh_newhashtable(qhT *qh, int newsize);
 vertexT *qh_newvertex(qhT *qh, pointT *point);
 ridgeT *qh_nextridge3d(qhT *qh, ridgeT *atridge, facetT *facet, vertexT **vertexp);
 void    qh_outcoplanar(qhT *qh /* qh.facet_list */);
 pointT *qh_point(qhT *qh, int id);
 void    qh_point_add(qhT *qh, setT *set, pointT *point, void *elem);
 setT   *qh_pointfacet(qhT *qh /*qh.facet_list*/);
 setT   *qh_pointvertex(qhT *qh /*qh.facet_list*/);
 void    qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist);
 void    qh_printhashtable(qhT *qh, FILE *fp);
 void    qh_printlists(qhT *qh);
 void    qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /*qh.newvertex_list newfacet_list visible_list*/);
 void    qh_setvoronoi_all(qhT *qh);
 void    qh_triangulate(qhT *qh /*qh.facet_list*/);
 void    qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex);
 void    qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
 void    qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB);
 void    qh_triangulate_null(qhT *qh, facetT *facetA);
 void    qh_vertexintersect(qhT *qh, setT **vertexsetA,setT *vertexsetB);
 setT   *qh_vertexintersect_new(qhT *qh, setT *vertexsetA,setT *vertexsetB);
 void    qh_vertexneighbors(qhT *qh /*qh.facet_list*/);
 boolT   qh_vertexsubset(qhT *qh, setT *vertexsetA, setT *vertexsetB);
 
 
 #endif /* qhDEFpoly */
diff --git a/src/libqhullr/qh-geom.htm b/src/libqhullr/qh-geom.htm
index 8aeab33..2e7c5e0 100644
--- a/src/libqhullr/qh-geom.htm
+++ b/src/libqhullr/qh-geom.htm
@@ -1,293 +1,293 @@
 
 
 
 
 geom.c, geom2.c -- geometric and floating point routines
 
 
 
 
 

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


geom.c, geom2.c, random.c -- geometric and floating point routines

Geometrically, a vertex is a point with d coordinates and a facet is a halfspace. A halfspace is defined by an oriented hyperplane through the facet's vertices. A hyperplane is defined by d normalized coefficients and an offset. A point is above a facet if its distance to the facet is positive.

Qhull uses floating point coordinates for input points, vertices, halfspace equations, centrums, and an interior point.

Qhull may be configured for single precision or double precision floating point arithmetic (see realT ).

Each floating point operation may incur round-off error (see Merge). The maximum error for distance computations is determined at initialization. The roundoff error in halfspace computation is accounted for by computing the distance from vertices to the halfspace.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to geom.c, geom2.c, geom.h, random.c, random.h

»geometric data types and constants

  • coordT coordinates and coefficients are stored as realT
  • pointT a point is an array of DIM3 coordinates

»mathematical macros

  • fabs_ returns the absolute value of a
  • fmax_ returns the maximum value of a and b
  • fmin_ returns the minimum value of a and b
  • maximize_ maximize a value
  • minimize_ minimize a value
  • det2_ compute a 2-d determinate
  • det3_ compute a 3-d determinate
  • dX, dY, dZ compute the difference between two coordinates

»mathematical functions

»computational geometry functions

»point array functions

»geometric facet functions

»geometric roundoff functions

  • qh_detjoggle determine default joggle for points and distance roundoff error
  • qh_detroundoff determine maximum roundoff error and other precision constants
  • qh_distround compute maximum roundoff error due to a distance computation to a normalized hyperplane
  • qh_divzero divide by a number that is nearly zero
  • qh_maxouter return maximum outer plane
  • qh_outerinner return actual outer and inner planes


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-globa.htm b/src/libqhullr/qh-globa.htm index d89f59c..51a4611 100644 --- a/src/libqhullr/qh-globa.htm +++ b/src/libqhullr/qh-globa.htm @@ -1,161 +1,161 @@ global.c -- global variables and their functions

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


global.c -- global variables and their functions

Qhull uses a global data structure, qh, to store globally defined constants, lists, sets, and variables. This allows multiple instances of Qhull to execute at the same time. The structure may be statically allocated or dynamically allocated with malloc(). See QHpointer.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to global.c and libqhull.h

»Qhull's global variables

»Global variable and initialization routines


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-io.htm b/src/libqhullr/qh-io.htm index 0ea8f48..0342809 100644 --- a/src/libqhullr/qh-io.htm +++ b/src/libqhullr/qh-io.htm @@ -1,303 +1,303 @@ io.c -- input and output operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


io.c -- input and output operations

Qhull provides a wide range of input and output options. To organize the code, most output formats use the same driver:

     qh_printbegin( fp, format, facetlist, facets, printall );
 
     FORALLfacet_( facetlist )
       qh_printafacet( fp, format, facet, printall );
 
     FOREACHfacet_( facets )
       qh_printafacet( fp, format, facet, printall );
 
     qh_printend( fp, format );
 

Note the 'printall' flag. It selects whether or not qh_skipfacet() is tested.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to io.c and io.h

»io.h constants and types

»User level functions

»Print functions for all output formats

»Text output functions

»Text utility functions

»Geomview output functions

»Geomview utility functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-mem.htm b/src/libqhullr/qh-mem.htm index 4bba0af..5aca0e1 100644 --- a/src/libqhullr/qh-mem.htm +++ b/src/libqhullr/qh-mem.htm @@ -1,141 +1,141 @@ mem.c -- memory operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


mem.c -- memory operations

Qhull uses quick-fit memory allocation. It maintains a set of free lists for a variety of small allocations. A small request returns a block from the best fitting free list. If the free list is empty, Qhull allocates a block from a reserved buffer.

Use 'T5' to trace memory allocations.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to mem.c and mem.h

»mem.h data types and constants

  • ptr_intT for casting a void* to an integer-type
  • qhmemT global memory structure for mem.c
  • qh_NOmem disable memory allocation

»mem.h macros

»User level functions

»Initialization and termination functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-merge.htm b/src/libqhullr/qh-merge.htm index 2bc92b4..625c555 100644 --- a/src/libqhullr/qh-merge.htm +++ b/src/libqhullr/qh-merge.htm @@ -1,364 +1,364 @@ merge.c -- facet merge operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


merge.c -- facet merge operations

Qhull handles precision problems by merged facets or joggled input. Except for redundant vertices, it corrects a problem by merging two facets. When done, all facets are clearly convex. See Imprecision in Qhull for further information.

Users may joggle the input ('QJn') instead of merging facets.

Qhull detects and corrects the following problems:

  • More than two facets meeting at a ridge. When Qhull creates facets, it creates an even number of facets for each ridge. A convex hull always has two facets for each ridge. More than two facets may be created if non-adjacent facets share a vertex. This is called a duplicate ridge. In 2-d, a duplicate ridge would create a loop of facets.
  • A facet contained in another facet. Facet merging may leave all vertices of one facet as a subset of the vertices of another facet. This is called a redundant facet.
  • A facet with fewer than three neighbors. Facet merging may leave a facet with one or two neighbors. This is called a degenerate facet.
  • A facet with flipped orientation. A facet's hyperplane may define a halfspace that does not include the interior point.This is called a flipped facet.
  • A coplanar horizon facet. A newly processed point may be coplanar with an horizon facet. Qhull creates a new facet without a hyperplane. It links new facets for the same horizon facet together. This is called a samecycle. The new facet or samecycle is merged into the horizon facet.
  • Concave facets. A facet's centrum may be above a neighboring facet. If so, the facets meet at a concave angle.
  • Coplanar facets. A facet's centrum may be coplanar with a neighboring facet (i.e., it is neither clearly below nor clearly above the facet's hyperplane). Qhull removes coplanar facets in independent sets sorted by angle.
  • Redundant vertex. A vertex may have fewer than three neighboring facets. If so, it is redundant and may be renamed to an adjacent vertex without changing the topological structure.This is called a redundant vertex.
-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to merge.c and merge.h

»merge.h data types, macros, and global sets

  • mergeT structure to identify a merge of two facets
  • FOREACHmerge_ assign 'merge' to each merge in merges
  • qh global sets qh.facet_mergeset contains non-convex merges while qh.degen_mergeset contains degenerate and redundant facets

»merge.h constants

»top-level merge functions

»functions for identifying merges

»functions for determining the best merge

»functions for merging facets

»functions for merging a cycle of facets

If a point is coplanar with an horizon facet, the corresponding new facets are linked together (a samecycle) for merging.

»functions for renaming a vertex

»functions for identifying vertices for renaming

»functions for check and trace


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-poly.htm b/src/libqhullr/qh-poly.htm index 1bb5937..abab924 100644 --- a/src/libqhullr/qh-poly.htm +++ b/src/libqhullr/qh-poly.htm @@ -1,481 +1,481 @@ poly.c, poly2.c -- polyhedron operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


poly.c, poly2.c -- polyhedron operations

Qhull uses dimension-free terminology. Qhull builds a polyhedron in dimension d. A polyhedron is a simplicial complex of faces with geometric information for the top and bottom-level faces. A (d-1)-face is a facet, a (d-2)-face is a ridge, and a 0-face is a vertex. For example in 3-d, a facet is a polygon and a ridge is an edge. A facet is built from a ridge (the base) and a vertex (the apex). See Qhull's data structures.

Qhull's primary data structure is a polyhedron. A polyhedron is a list of facets. Each facet has a set of neighboring facets and a set of vertices. Each facet has a hyperplane. For example, a tetrahedron has four facets. If its vertices are a, b, c, d, and its facets are 1, 2, 3, 4, the tetrahedron is

  • facet 1
    • vertices: b c d
    • neighbors: 2 3 4
  • facet 2
    • vertices: a c d
    • neighbors: 1 3 4
  • facet 3
    • vertices: a b d
    • neighbors: 1 2 4
  • facet 4
    • vertices: a b c
    • neighbors: 1 2 3

A facet may be simplicial or non-simplicial. In 3-d, a simplicial facet has three vertices and three neighbors. A nonsimplicial facet has more than three vertices and more than three neighbors. A nonsimplicial facet has a set of ridges and a centrum.

A simplicial facet has an orientation. An orientation is either top or bottom. The flag, facet->toporient, defines the orientation of the facet's vertices. For example in 3-d, 'top' is left-handed orientation (i.e., the vertex order follows the direction of the left-hand fingers when the thumb is pointing away from the center). Except for axis-parallel facets in 5-d and higher, topological orientation determines the geometric orientation of the facet's hyperplane.

A nonsimplicial facet is due to merging two or more facets. The facet's ridge set determine a simplicial decomposition of the facet. Each ridge is a 1-face (i.e., it has two vertices and two neighboring facets). The orientation of a ridge is determined by the order of the neighboring facets. The flag, facet->toporient,is ignored.

A nonsimplicial facet has a centrum for testing convexity. A centrum is a point on the facet's hyperplane that is near the center of the facet. Except for large facets, it is the arithmetic average of the facet's vertices.

A nonsimplicial facet is an approximation that is defined by offsets from the facet's hyperplane. When Qhull finishes, the outer plane is above all points while the inner plane is below the facet's vertices. This guarantees that any exact convex hull passes between the inner and outer planes. The outer plane is defined by facet->maxoutside while the inner plane is computed from the facet's vertices.

Qhull 3.1 includes triangulation of non-simplicial facets ('Qt'). These facets, called tricoplanar, share the same normal. centrum, and Voronoi center. One facet (keepcentrum) owns these data structures. While tricoplanar facets are more accurate than the simplicial facets from joggled input, they may have zero area or flipped orientation.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to poly.c, poly2.c, poly.h, and libqhull.h

»Data types and global lists for polyhedrons

»poly.h constants

  • ALGORITHMfault flag to not report errors in qh_checkconvex()
  • DATAfault flag to report errors in qh_checkconvex()
  • DUPLICATEridge special value for facet->neighbor to indicate a duplicate ridge
  • MERGEridge special value for facet->neighbor to indicate a merged ridge

»Global FORALL macros

»FORALL macros

»FOREACH macros

»Indexed FOREACH macros

  • FOREACHfacet_i_ assign 'facet' and 'facet_i' to each facet in facet set
  • FOREACHneighbor_i_ assign 'neighbor' and 'neighbor_i' to each facet in facet->neighbors or vertex->neighbors
  • FOREACHpoint_i_ assign 'point' and 'point_i' to each point in points set
  • FOREACHridge_i_ assign 'ridge' and 'ridge_i' to each ridge in ridges set
  • FOREACHvertex_i_ assign 'vertex' and 'vertex_i' to each vertex in vertices set
  • FOREACHvertexreverse12_ assign 'vertex' to each vertex in vertex set; reverse the order of first two vertices

»Other macros for polyhedrons

  • getid_ return ID for a facet, ridge, or vertex
  • otherfacet_ return neighboring facet for a ridge in a facet

»Facetlist functions

»Facet functions

»Vertex, ridge, and point functions

»Hashtable functions

»Allocation and deallocation functions

»Check functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-qhull.htm b/src/libqhullr/qh-qhull.htm index df877f3..4962dca 100644 --- a/src/libqhullr/qh-qhull.htm +++ b/src/libqhullr/qh-qhull.htm @@ -1,277 +1,277 @@ libqhull.c -- top-level functions and basic data types

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


libqhull.c -- top-level functions and basic data types

Qhull implements the Quickhull algorithm for computing the convex hull. The Quickhull algorithm combines two well-known algorithms: the 2-d quickhull algorithm and the n-d beneath-beyond algorithm. See Description of Qhull.

This section provides an index to the top-level functions and base data types. The top-level header file, libqhull.h, contains prototypes for these functions.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to libqhull.c, libqhull.h, and unix.c

»libqhull.h and unix.c data types and constants

  • flagT Boolean flag as a bit
  • boolT boolean value, either True or False
  • CENTERtype to distinguish facet->center
  • qh_PRINT output formats for printing (qh.PRINTout)
  • qh_ALL argument flag for selecting everything
  • qh_ERR Qhull exit codes for indicating errors
  • qh_FILEstderr Fake stderr to distinguish error output from normal output [C++ only]
  • qh_prompt version and long prompt for Qhull
  • qh_prompt2 synopsis for Qhull
  • qh_prompt3 concise prompt for Qhull
  • qh_version version stamp

»libqhull.h other macros

  • traceN print trace message if qh.IStracing >= N.
  • QHULL_UNUSED declare an unused variable to avoid warnings.

»Quickhull routines in call order

»Top-level routines for initializing and terminating Qhull (in other modules)

»Top-level routines for reading and modifying the input (in other modules)

»Top-level routines for calling Qhull (in other modules)

»Top-level routines for returning results (in other modules)

»Top-level routines for testing and debugging (in other modules)


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-set.htm b/src/libqhullr/qh-set.htm index 1fbd366..e07a610 100644 --- a/src/libqhullr/qh-set.htm +++ b/src/libqhullr/qh-set.htm @@ -1,306 +1,306 @@ qset.c -- set data type and operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


qset.c -- set data type and operations

Qhull's data structures are constructed from sets. The functions and macros in qset.c construct, iterate, and modify these sets. They are the most frequently called functions in Qhull. For this reason, efficiency is the primary concern.

In Qhull, a set is represented by an unordered array of pointers with a maximum size and a NULL terminator (setT). Most sets correspond to mathematical sets (i.e., the pointers are unique). Some sets are sorted to enforce uniqueness. Some sets are ordered. For example, the order of vertices in a ridge determine the ridge's orientation. If you reverse the order of adjacent vertices, the orientation reverses. Some sets are not mathematical sets. They may be indexed as an array and they may include NULL pointers.

The most common operation on a set is to iterate its members. This is done with a 'FOREACH...' macro. Each set has a custom macro. For example, 'FOREACHvertex_' iterates over a set of vertices. Each vertex is assigned to the variable 'vertex' from the pointer 'vertexp'.

Most sets are constructed by appending elements to the set. The last element of a set is either NULL or the index of the terminating NULL for a partially full set. If a set is full, appending an element copies the set to a larger array.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to qset.c and qset.h

»Data types and constants

  • SETelemsize size of a set element in bytes
  • setT a set with a maximum size and a current size
  • qh global sets global sets for temporary sets, etc.

»FOREACH macros

»Access and size macros

»Internal macros

  • SETsizeaddr_ return pointer to end element of a set (indicates current size)

»address macros

  • SETaddr_ return address of a set's elements
  • SETelemaddr_ return address of the n'th element of a set
  • SETref_ l.h.s. for modifying the current element in a FOREACH iteration

»Allocation and deallocation functions

»Access and predicate functions

»Add functions

»Check and print functions

»Copy, compact, and zero functions

»Delete functions

»Temporary set functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-stat.htm b/src/libqhullr/qh-stat.htm index 53c6158..90bc791 100644 --- a/src/libqhullr/qh-stat.htm +++ b/src/libqhullr/qh-stat.htm @@ -1,161 +1,161 @@ stat.c -- statistical operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


stat.c -- statistical operations

Qhull records many statistics. These functions and macros make it inexpensive to add a statistic.

As with Qhull's global variables, the statistics data structure is accessed by a macro, 'qhstat'. If qh_QHpointer is defined, the macro is 'qh_qhstat->', otherwise the macro is 'qh_qhstat.'. Statistics may be turned off in user.h. If so, all but the 'zz' statistics are ignored.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to stat.c and stat.h

»stat.h types

  • intrealT union of integer and real
  • qhstat global data structure for statistics

»stat.h constants

  • qh_KEEPstatistics 0 turns off most statistics
  • Z..., W... integer (Z) and real (W) statistics
  • ZZstat Z.../W... statistics that remain defined if qh_KEEPstatistics=0
  • ztype zdoc, zinc, etc. for definining statistics

»stat.h macros

  • MAYdebugx called frequently for error trapping
  • zadd_/wadd_ add value to an integer or real statistic
  • zdef_ define a statistic
  • zinc_ increment an integer statistic
  • zmax_/wmax_ update integer or real maximum statistic
  • zmin_/wmin_ update integer or real minimum statistic
  • zval_/wval_ set or return value of a statistic

»stat.c functions


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qh-user.htm b/src/libqhullr/qh-user.htm index b917920..1525f2b 100644 --- a/src/libqhullr/qh-user.htm +++ b/src/libqhullr/qh-user.htm @@ -1,265 +1,265 @@ user.c -- user-definable operations

Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


user.c -- user-definable operations

This section contains functions and constants that the user may want to change.

-

Copyright © 1995-2012 C.B. Barber

+

Copyright © 1995-2015 C.B. Barber


» Geom GlobalIoMemMergePolyQhullSetStatUser

Index to user.c, usermem.c, userprintf.c, userprintf_rbox.c and user.h

»Qhull library constants

»user.h data types and configuration macros

»definition constants

  • qh_DEFAULTbox define default box size for rbox, 'Qbb', and 'QbB' (Geomview expects 0.5)
  • qh_INFINITE on output, indicates Voronoi center at infinity
  • qh_ORIENTclock define convention for orienting facets
  • qh_ZEROdelaunay define facets that are ignored in Delaunay triangulations

»joggle constants

»performance related constants

»memory constants

»conditional compilation

»merge constants

»user.c functions

»usermem.c functions

  • qh_exit exit program, same as exit().
  • qh_free free memory, same as free().
  • qh_malloc allocate memory, same as malloc()

»userprintf.c and userprintf_rbox,c functions

  • qh_fprintf print information from Qhull, sames as fprintf().
  • qh_fprintf_rbox print information from Rbox, sames as fprintf().


Up: Home page for Qhull
Up: Qhull manual: Table of Contents
Up: ProgramsOptionsOutputFormatsGeomviewPrintQhullPrecisionTrace
Up: Qhull code: Table of Contents
To: Qhull functions, macros, and data structures
To: GeomGlobalIoMemMergePolyQhullSetStatUser


The Geometry Center Home Page

Comments to: qhull@qhull.org
Created: May 2, 1997 --- Last modified: see top

diff --git a/src/libqhullr/qhull_ra.h b/src/libqhullr/qhull_ra.h index 552e973..ce986be 100644 --- a/src/libqhullr/qhull_ra.h +++ b/src/libqhullr/qhull_ra.h @@ -1,151 +1,151 @@ /*
  ---------------------------------
 
    qhull_ra.h
    all header files for compiling qhull with reentrant code
 
    see qh-qhull.htm
 
    see libqhull_r.h for user-level definitions
 
    see user_r.h for user-definable constants
 
    defines internal functions for libqhull_r.c global_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/qhull_ra.h#7 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/qhull_ra.h#8 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
            full parens around (x?y:z)
            use '#include qhull/qhull_ra.h' to avoid name clashes
 */
 
 #ifndef qhDEFqhulla
 #define qhDEFqhulla 1
 
 #include "libqhull_r.h"  /* Defines data types */
 
 #include "stat_r.h"
 #include "random_r.h"
 #include "mem_r.h"
 #include "qset_r.h"
 #include "geom_r.h"
 #include "merge_r.h"
 #include "poly_r.h"
 #include "io_r.h"
 
 #include 
 #include 
 #include 
 #include     /* some compilers will not need float.h */
 #include 
 #include 
 #include 
 #include 
 #include 
 /*** uncomment here and qset_r.c
      if string.h does not define memcpy()
 #include 
 */
 
 #if qh_CLOCKtype == 2  /* defined in user_r.h from libqhull_r.h */
 #include 
 #include 
 #include 
 #endif
 
 #ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
 #pragma warning( disable : 4100)  /* unreferenced formal parameter */
 #pragma warning( disable : 4127)  /* conditional expression is constant */
 #pragma warning( disable : 4706)  /* assignment within conditional function */
 #pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
 #endif
 
 /* ======= -macros- =========== */
 
 /*----------------------------------
 
   traceN((qh, qh->ferr, 0Nnnn, "format\n", vars));
     calls qh_fprintf if qh.IStracing >= N
 
     Add debugging traps to the end of qh_fprintf
 
   notes:
     removing tracing reduces code size but doesn't change execution speed
 */
 #ifndef qh_NOtrace
 #define trace0(args) {if (qh->IStracing) qh_fprintf args;}
 #define trace1(args) {if (qh->IStracing >= 1) qh_fprintf args;}
 #define trace2(args) {if (qh->IStracing >= 2) qh_fprintf args;}
 #define trace3(args) {if (qh->IStracing >= 3) qh_fprintf args;}
 #define trace4(args) {if (qh->IStracing >= 4) qh_fprintf args;}
 #define trace5(args) {if (qh->IStracing >= 5) qh_fprintf args;}
 #else /* qh_NOtrace */
 #define trace0(args) {}
 #define trace1(args) {}
 #define trace2(args) {}
 #define trace3(args) {}
 #define trace4(args) {}
 #define trace5(args) {}
 #endif /* qh_NOtrace */
 
 /*----------------------------------
 
 */
 
 /* See Qt's qglobal.h */
 #if !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
 #   define QHULL_OS_WIN
 #elif defined(__MWERKS__) && defined(__INTEL__)
 #   define QHULL_OS_WIN
 #endif
 #if defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN)
 template 
 inline void qhullUnused(T &x) { (void)x; }
 #  define QHULL_UNUSED(x) qhullUnused(x);
 #else
 #  define QHULL_UNUSED(x) (void)x;
 #endif
 
 /***** -libqhull_r.c prototypes (alphabetical after qhull) ********************/
 
 void    qh_qhull(qhT *qh);
 boolT   qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist);
 void    qh_buildhull(qhT *qh);
 void    qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet);
 void    qh_build_withrestart(qhT *qh);
 void    qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet);
 void    qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
 pointT *qh_nextfurthest(qhT *qh, facetT **visible);
 void    qh_partitionall(qhT *qh, setT *vertices, pointT *points,int npoints);
 void    qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist);
 void    qh_partitionpoint(qhT *qh, pointT *point, facetT *facet);
 void    qh_partitionvisible(qhT *qh, boolT allpoints, int *numpoints);
 void    qh_precision(qhT *qh, const char *reason);
 void    qh_printsummary(qhT *qh, FILE *fp);
 
 /***** -global_r.c internal prototypes (alphabetical) ***********************/
 
 void    qh_appendprint(qhT *qh, qh_PRINT format);
 void    qh_freebuild(qhT *qh, boolT allmem);
 void    qh_freebuffers(qhT *qh);
 void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
 
 /***** -stat_r.c internal prototypes (alphabetical) ***********************/
 
 void    qh_allstatA(qhT *qh);
 void    qh_allstatB(qhT *qh);
 void    qh_allstatC(qhT *qh);
 void    qh_allstatD(qhT *qh);
 void    qh_allstatE(qhT *qh);
 void    qh_allstatE2(qhT *qh);
 void    qh_allstatF(qhT *qh);
 void    qh_allstatG(qhT *qh);
 void    qh_allstatH(qhT *qh);
 void    qh_freebuffers(qhT *qh);
 void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
 
 #endif /* qhDEFqhulla */
diff --git a/src/libqhullr/qset_r.c b/src/libqhullr/qset_r.c
index 724d5b4..be4ddd5 100644
--- a/src/libqhullr/qset_r.c
+++ b/src/libqhullr/qset_r.c
@@ -1,1340 +1,1340 @@
 /*
  ---------------------------------
 
    qset_r.c
    implements set manipulations needed for quickhull
 
    see qh-set.htm and qset_r.h
 
    Be careful of strict aliasing (two pointers of different types
    that reference the same location).  The last slot of a set is
    either the actual size of the set plus 1, or the NULL terminator
    of the set (i.e., setelemT).
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/qset_r.c#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/qset_r.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qset_r.h"
 #include "libqhull_r.h" /* for qhT */
 #include "mem_r.h"
 #include 
 #include 
 /*** uncomment here and qhull_ra.h
      if string.h does not define memcpy()
 #include 
 */
 
 #ifndef qhDEFlibqhull
 typedef struct ridgeT ridgeT;
 typedef struct facetT facetT;
 void    qh_errexit(qhT *qh, int exitcode, facetT *, ridgeT *);
 void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
 #  ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
 #  pragma warning( disable : 4127)  /* conditional expression is constant */
 #  pragma warning( disable : 4706)  /* assignment within conditional function */
 #  endif
 #endif
 
 /*=============== internal macros ===========================*/
 
 /*============ functions in alphabetical order ===================*/
 
 /*----------------------------------
 
   qh_setaddnth(qh, setp, nth, newelem)
     adds newelem as n'th element of sorted or unsorted *setp
 
   notes:
     *setp and newelem must be defined
     *setp may be a temp set
     nth=0 is first element
     errors if nth is out of bounds
 
   design:
     expand *setp if empty or full
     move tail of *setp up one
     insert newelem
 */
 void qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem) {
   int oldsize, i;
   setelemT *sizep;          /* avoid strict aliasing */
   setelemT *oldp, *newp;
 
   if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
     qh_setlarger(qh, setp);
     sizep= SETsizeaddr_(*setp);
   }
   oldsize= sizep->i - 1;
   if (nth < 0 || nth > oldsize) {
     qh_fprintf(qh, qh->qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qh, qh->qhmem.ferr, "", *setp);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   sizep->i++;
   oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void);   /* NULL */
   newp= oldp+1;
   for (i=oldsize-nth+1; i--; )  /* move at least NULL  */
     (newp--)->p= (oldp--)->p;       /* may overwrite *sizep */
   newp->p= newelem;
 } /* setaddnth */
 
 
 /*----------------------------------
 
   setaddsorted( setp, newelem )
     adds an newelem into sorted *setp
 
   notes:
     *setp and newelem must be defined
     *setp may be a temp set
     nop if newelem already in set
 
   design:
     find newelem's position in *setp
     insert newelem
 */
 void qh_setaddsorted(qhT *qh, setT **setp, void *newelem) {
   int newindex=0;
   void *elem, **elemp;
 
   FOREACHelem_(*setp) {          /* could use binary search instead */
     if (elem < newelem)
       newindex++;
     else if (elem == newelem)
       return;
     else
       break;
   }
   qh_setaddnth(qh, setp, newindex, newelem);
 } /* setaddsorted */
 
 
 /*---------------------------------
 
   qh_setappend(qh, setp, newelem)
     append newelem to *setp
 
   notes:
     *setp may be a temp set
     *setp and newelem may be NULL
 
   design:
     expand *setp if empty or full
     append newelem to *setp
 
 */
 void qh_setappend(qhT *qh, setT **setp, void *newelem) {
   setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
   setelemT *endp;
   int count;
 
   if (!newelem)
     return;
   if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
     qh_setlarger(qh, setp);
     sizep= SETsizeaddr_(*setp);
   }
   count= (sizep->i)++ - 1;
   endp= (setelemT *)SETelemaddr_(*setp, count, void);
   (endp++)->p= newelem;
   endp->p= NULL;
 } /* setappend */
 
 /*---------------------------------
 
   qh_setappend_set(qh, setp, setA)
     appends setA to *setp
 
   notes:
     *setp can not be a temp set
     *setp and setA may be NULL
 
   design:
     setup for copy
     expand *setp if it is too small
     append all elements of setA to *setp
 */
 void qh_setappend_set(qhT *qh, setT **setp, setT *setA) {
   int sizeA, size;
   setT *oldset;
   setelemT *sizep;
 
   if (!setA)
     return;
   SETreturnsize_(setA, sizeA);
   if (!*setp)
     *setp= qh_setnew(qh, sizeA);
   sizep= SETsizeaddr_(*setp);
   if (!(size= sizep->i))
     size= (*setp)->maxsize;
   else
     size--;
   if (size + sizeA > (*setp)->maxsize) {
     oldset= *setp;
     *setp= qh_setcopy(qh, oldset, sizeA);
     qh_setfree(qh, &oldset);
     sizep= SETsizeaddr_(*setp);
   }
   if (sizeA > 0) {
     sizep->i= size+sizeA+1;   /* memcpy may overwrite */
     memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
   }
 } /* setappend_set */
 
 
 /*---------------------------------
 
   qh_setappend2ndlast(qh, setp, newelem )
     makes newelem the next to the last element in *setp
 
   notes:
     *setp must have at least one element
     newelem must be defined
     *setp may be a temp set
 
   design:
     expand *setp if empty or full
     move last element of *setp up one
     insert newelem
 */
 void qh_setappend2ndlast(qhT *qh, setT **setp, void *newelem) {
     setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
     setelemT *endp, *lastp;
     int count;
 
     if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
         qh_setlarger(qh, setp);
         sizep= SETsizeaddr_(*setp);
     }
     count= (sizep->i)++ - 1;
     endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
     lastp= endp-1;
     *(endp++)= *lastp;
     endp->p= NULL;    /* may overwrite *sizep */
     lastp->p= newelem;
 } /* setappend2ndlast */
 
 /*---------------------------------
 
   qh_setcheck(qh, set, typename, id )
     check set for validity
     report errors with typename and id
 
   design:
     checks that maxsize, actual size, and NULL terminator agree
 */
 void qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned id) {
   int maxsize, size;
   int waserr= 0;
 
   if (!set)
     return;
   SETreturnsize_(set, size);
   maxsize= set->maxsize;
   if (size > maxsize || !maxsize) {
     qh_fprintf(qh, qh->qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
              size, tname, id, maxsize);
     waserr= 1;
   }else if (set->e[size].p) {
     qh_fprintf(qh, qh->qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
              tname, id, size-1, maxsize);
     waserr= 1;
   }
   if (waserr) {
     qh_setprint(qh, qh->qhmem.ferr, "ERRONEOUS", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
 } /* setcheck */
 
 
 /*---------------------------------
 
   qh_setcompact(qh, set )
     remove internal NULLs from an unsorted set
 
   returns:
     updated set
 
   notes:
     set may be NULL
     it would be faster to swap tail of set into holes, like qh_setdel
 
   design:
     setup pointers into set
     skip NULLs while copying elements to start of set
     update the actual size
 */
 void qh_setcompact(qhT *qh, setT *set) {
   int size;
   void **destp, **elemp, **endp, **firstp;
 
   if (!set)
     return;
   SETreturnsize_(set, size);
   destp= elemp= firstp= SETaddr_(set, void);
   endp= destp + size;
   while (1) {
     if (!(*destp++ = *elemp++)) {
       destp--;
       if (elemp > endp)
         break;
     }
   }
   qh_settruncate(qh, set, (int)(destp-firstp));   /* WARN64 */
 } /* setcompact */
 
 
 /*---------------------------------
 
   qh_setcopy(qh, set, extra )
     make a copy of a sorted or unsorted set with extra slots
 
   returns:
     new set
 
   design:
     create a newset with extra slots
     copy the elements to the newset
 
 */
 setT *qh_setcopy(qhT *qh, setT *set, int extra) {
   setT *newset;
   int size;
 
   if (extra < 0)
     extra= 0;
   SETreturnsize_(set, size);
   newset= qh_setnew(qh, size+extra);
   SETsizeaddr_(newset)->i= size+1;    /* memcpy may overwrite */
   memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
   return(newset);
 } /* setcopy */
 
 
 /*---------------------------------
 
   qh_setdel(set, oldelem )
     delete oldelem from an unsorted set
 
   returns:
     returns oldelem if found
     returns NULL otherwise
 
   notes:
     set may be NULL
     oldelem must not be NULL;
     only deletes one copy of oldelem in set
 
   design:
     locate oldelem
     update actual size if it was full
     move the last element to the oldelem's location
 */
 void *qh_setdel(setT *set, void *oldelem) {
   setelemT *sizep;
   setelemT *elemp;
   setelemT *lastp;
 
   if (!set)
     return NULL;
   elemp= (setelemT *)SETaddr_(set, void);
   while (elemp->p != oldelem && elemp->p)
     elemp++;
   if (elemp->p) {
     sizep= SETsizeaddr_(set);
     if (!(sizep->i)--)         /*  if was a full set */
       sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
     lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
     elemp->p= lastp->p;      /* may overwrite itself */
     lastp->p= NULL;
     return oldelem;
   }
   return NULL;
 } /* setdel */
 
 
 /*---------------------------------
 
   qh_setdellast(set)
     return last element of set or NULL
 
   notes:
     deletes element from set
     set may be NULL
 
   design:
     return NULL if empty
     if full set
       delete last element and set actual size
     else
       delete last element and update actual size
 */
 void *qh_setdellast(setT *set) {
   int setsize;  /* actually, actual_size + 1 */
   int maxsize;
   setelemT *sizep;
   void *returnvalue;
 
   if (!set || !(set->e[0].p))
     return NULL;
   sizep= SETsizeaddr_(set);
   if ((setsize= sizep->i)) {
     returnvalue= set->e[setsize - 2].p;
     set->e[setsize - 2].p= NULL;
     sizep->i--;
   }else {
     maxsize= set->maxsize;
     returnvalue= set->e[maxsize - 1].p;
     set->e[maxsize - 1].p= NULL;
     sizep->i= maxsize;
   }
   return returnvalue;
 } /* setdellast */
 
 
 /*---------------------------------
 
   qh_setdelnth(qh, set, nth )
     deletes nth element from unsorted set
     0 is first element
 
   returns:
     returns the element (needs type conversion)
 
   notes:
     errors if nth invalid
 
   design:
     setup points and check nth
     delete nth element and overwrite with last element
 */
 void *qh_setdelnth(qhT *qh, setT *set, int nth) {
   void *elem;
   setelemT *sizep;
   setelemT *elemp, *lastp;
 
   elemp= (setelemT *)SETelemaddr_(set, nth, void);
   sizep= SETsizeaddr_(set);
   if ((sizep->i--)==0)         /*  if was a full set */
     sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
   if (nth < 0 || nth >= sizep->i) {
     qh_fprintf(qh, qh->qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qh, qh->qhmem.ferr, "", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
   elem= elemp->p;
   elemp->p= lastp->p;      /* may overwrite itself */
   lastp->p= NULL;
   return elem;
 } /* setdelnth */
 
 /*---------------------------------
 
   qh_setdelnthsorted(qh, set, nth )
     deletes nth element from sorted set
 
   returns:
     returns the element (use type conversion)
 
   notes:
     errors if nth invalid
 
   see also:
     setnew_delnthsorted
 
   design:
     setup points and check nth
     copy remaining elements down one
     update actual size
 */
 void *qh_setdelnthsorted(qhT *qh, setT *set, int nth) {
   void *elem;
   setelemT *sizep;
   setelemT *newp, *oldp;
 
   sizep= SETsizeaddr_(set);
   if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
     qh_fprintf(qh, qh->qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qh, qh->qhmem.ferr, "", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   newp= (setelemT *)SETelemaddr_(set, nth, void);
   elem= newp->p;
   oldp= newp+1;
   while (((newp++)->p= (oldp++)->p))
     ; /* copy remaining elements and NULL */
   if ((sizep->i--)==0)         /*  if was a full set */
     sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
   return elem;
 } /* setdelnthsorted */
 
 
 /*---------------------------------
 
   qh_setdelsorted(set, oldelem )
     deletes oldelem from sorted set
 
   returns:
     returns oldelem if it was deleted
 
   notes:
     set may be NULL
 
   design:
     locate oldelem in set
     copy remaining elements down one
     update actual size
 */
 void *qh_setdelsorted(setT *set, void *oldelem) {
   setelemT *sizep;
   setelemT *newp, *oldp;
 
   if (!set)
     return NULL;
   newp= (setelemT *)SETaddr_(set, void);
   while(newp->p != oldelem && newp->p)
     newp++;
   if (newp->p) {
     oldp= newp+1;
     while (((newp++)->p= (oldp++)->p))
       ; /* copy remaining elements */
     sizep= SETsizeaddr_(set);
     if ((sizep->i--)==0)    /*  if was a full set */
       sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
     return oldelem;
   }
   return NULL;
 } /* setdelsorted */
 
 
 /*---------------------------------
 
   qh_setduplicate(qh, set, elemsize )
     duplicate a set of elemsize elements
 
   notes:
     use setcopy if retaining old elements
 
   design:
     create a new set
     for each elem of the old set
       create a newelem
       append newelem to newset
 */
 setT *qh_setduplicate(qhT *qh, setT *set, int elemsize) {
   void          *elem, **elemp, *newElem;
   setT          *newSet;
   int           size;
 
   if (!(size= qh_setsize(qh, set)))
     return NULL;
   newSet= qh_setnew(qh, size);
   FOREACHelem_(set) {
     newElem= qh_memalloc(qh, elemsize);
     memcpy(newElem, elem, (size_t)elemsize);
     qh_setappend(qh, &newSet, newElem);
   }
   return newSet;
 } /* setduplicate */
 
 
 /*---------------------------------
 
   qh_setendpointer( set )
     Returns pointer to NULL terminator of a set's elements
     set can not be NULL
 
 */
 void **qh_setendpointer(setT *set) {
 
   setelemT *sizep= SETsizeaddr_(set);
   int n= sizep->i;
   return (n ? &set->e[n-1].p : &sizep->p);
 } /* qh_setendpointer */
 
 /*---------------------------------
 
   qh_setequal( setA, setB )
     returns 1 if two sorted sets are equal, otherwise returns 0
 
   notes:
     either set may be NULL
 
   design:
     check size of each set
     setup pointers
     compare elements of each set
 */
 int qh_setequal(setT *setA, setT *setB) {
   void **elemAp, **elemBp;
   int sizeA= 0, sizeB= 0;
 
   if (setA) {
     SETreturnsize_(setA, sizeA);
   }
   if (setB) {
     SETreturnsize_(setB, sizeB);
   }
   if (sizeA != sizeB)
     return 0;
   if (!sizeA)
     return 1;
   elemAp= SETaddr_(setA, void);
   elemBp= SETaddr_(setB, void);
   if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
     return 1;
   return 0;
 } /* setequal */
 
 
 /*---------------------------------
 
   qh_setequal_except( setA, skipelemA, setB, skipelemB )
     returns 1 if sorted setA and setB are equal except for skipelemA & B
 
   returns:
     false if either skipelemA or skipelemB are missing
 
   notes:
     neither set may be NULL
 
     if skipelemB is NULL,
       can skip any one element of setB
 
   design:
     setup pointers
     search for skipelemA, skipelemB, and mismatches
     check results
 */
 int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
   void **elemA, **elemB;
   int skip=0;
 
   elemA= SETaddr_(setA, void);
   elemB= SETaddr_(setB, void);
   while (1) {
     if (*elemA == skipelemA) {
       skip++;
       elemA++;
     }
     if (skipelemB) {
       if (*elemB == skipelemB) {
         skip++;
         elemB++;
       }
     }else if (*elemA != *elemB) {
       skip++;
       if (!(skipelemB= *elemB++))
         return 0;
     }
     if (!*elemA)
       break;
     if (*elemA++ != *elemB++)
       return 0;
   }
   if (skip != 2 || *elemB)
     return 0;
   return 1;
 } /* setequal_except */
 
 
 /*---------------------------------
 
   qh_setequal_skip( setA, skipA, setB, skipB )
     returns 1 if sorted setA and setB are equal except for elements skipA & B
 
   returns:
     false if different size
 
   notes:
     neither set may be NULL
 
   design:
     setup pointers
     search for mismatches while skipping skipA and skipB
 */
 int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
   void **elemA, **elemB, **skipAp, **skipBp;
 
   elemA= SETaddr_(setA, void);
   elemB= SETaddr_(setB, void);
   skipAp= SETelemaddr_(setA, skipA, void);
   skipBp= SETelemaddr_(setB, skipB, void);
   while (1) {
     if (elemA == skipAp)
       elemA++;
     if (elemB == skipBp)
       elemB++;
     if (!*elemA)
       break;
     if (*elemA++ != *elemB++)
       return 0;
   }
   if (*elemB)
     return 0;
   return 1;
 } /* setequal_skip */
 
 
 /*---------------------------------
 
   qh_setfree(qh, setp )
     frees the space occupied by a sorted or unsorted set
 
   returns:
     sets setp to NULL
 
   notes:
     set may be NULL
 
   design:
     free array
     free set
 */
 void qh_setfree(qhT *qh, setT **setp) {
   int size;
   void **freelistp;  /* used !qh_NOmem */
 
   if (*setp) {
     size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
     if (size <= qh->qhmem.LASTsize) {
       qh_memfree_(qh, *setp, size, freelistp);
     }else
       qh_memfree(qh, *setp, size);
     *setp= NULL;
   }
 } /* setfree */
 
 
 /*---------------------------------
 
   qh_setfree2(qh, setp, elemsize )
     frees the space occupied by a set and its elements
 
   notes:
     set may be NULL
 
   design:
     free each element
     free set
 */
 void qh_setfree2(qhT *qh, setT **setp, int elemsize) {
   void          *elem, **elemp;
 
   FOREACHelem_(*setp)
     qh_memfree(qh, elem, elemsize);
   qh_setfree(qh, setp);
 } /* setfree2 */
 
 
 
 /*---------------------------------
 
   qh_setfreelong(qh, setp )
     frees a set only if it's in long memory
 
   returns:
     sets setp to NULL if it is freed
 
   notes:
     set may be NULL
 
   design:
     if set is large
       free it
 */
 void qh_setfreelong(qhT *qh, setT **setp) {
   int size;
 
   if (*setp) {
     size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
     if (size > qh->qhmem.LASTsize) {
       qh_memfree(qh, *setp, size);
       *setp= NULL;
     }
   }
 } /* setfreelong */
 
 
 /*---------------------------------
 
   qh_setin(set, setelem )
     returns 1 if setelem is in a set, 0 otherwise
 
   notes:
     set may be NULL or unsorted
 
   design:
     scans set for setelem
 */
 int qh_setin(setT *set, void *setelem) {
   void *elem, **elemp;
 
   FOREACHelem_(set) {
     if (elem == setelem)
       return 1;
   }
   return 0;
 } /* setin */
 
 
 /*---------------------------------
 
   qh_setindex(set, atelem )
     returns the index of atelem in set.
     returns -1, if not in set or maxsize wrong
 
   notes:
     set may be NULL and may contain nulls.
     NOerrors returned (qh_pointid, QhullPoint::id)
 
   design:
     checks maxsize
     scans set for atelem
 */
 int qh_setindex(setT *set, void *atelem) {
   void **elem;
   int size, i;
 
   if (!set)
     return -1;
   SETreturnsize_(set, size);
   if (size > set->maxsize)
     return -1;
   elem= SETaddr_(set, void);
   for (i=0; i < size; i++) {
     if (*elem++ == atelem)
       return i;
   }
   return -1;
 } /* setindex */
 
 
 /*---------------------------------
 
   qh_setlarger(qh, oldsetp )
     returns a larger set that contains all elements of *oldsetp
 
   notes:
     the set is at least twice as large
     if temp set, updates qh->qhmem.tempstack
 
   design:
     creates a new set
     copies the old set to the new set
     updates pointers in tempstack
     deletes the old set
 */
 void qh_setlarger(qhT *qh, setT **oldsetp) {
   int size= 1;
   setT *newset, *set, **setp, *oldset;
   setelemT *sizep;
   setelemT *newp, *oldp;
 
   if (*oldsetp) {
     oldset= *oldsetp;
     SETreturnsize_(oldset, size);
     qh->qhmem.cntlarger++;
     qh->qhmem.totlarger += size+1;
     newset= qh_setnew(qh, 2 * size);
     oldp= (setelemT *)SETaddr_(oldset, void);
     newp= (setelemT *)SETaddr_(newset, void);
     memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize);
     sizep= SETsizeaddr_(newset);
     sizep->i= size+1;
     FOREACHset_((setT *)qh->qhmem.tempstack) {
       if (set == oldset)
         *(setp-1)= newset;
     }
     qh_setfree(qh, oldsetp);
   }else
     newset= qh_setnew(qh, 3);
   *oldsetp= newset;
 } /* setlarger */
 
 
 /*---------------------------------
 
   qh_setlast( set )
     return last element of set or NULL (use type conversion)
 
   notes:
     set may be NULL
 
   design:
     return last element
 */
 void *qh_setlast(setT *set) {
   int size;
 
   if (set) {
     size= SETsizeaddr_(set)->i;
     if (!size)
       return SETelem_(set, set->maxsize - 1);
     else if (size > 1)
       return SETelem_(set, size - 2);
   }
   return NULL;
 } /* setlast */
 
 
 /*---------------------------------
 
   qh_setnew(qh, setsize )
     creates and allocates space for a set
 
   notes:
     setsize means the number of elements (!including the NULL terminator)
     use qh_settemp/qh_setfreetemp if set is temporary
 
   design:
     allocate memory for set
     roundup memory if small set
     initialize as empty set
 */
 setT *qh_setnew(qhT *qh, int setsize) {
   setT *set;
   int sizereceived; /* used !qh_NOmem */
   int size;
   void **freelistp; /* used !qh_NOmem */
 
   if (!setsize)
     setsize++;
   size= sizeof(setT) + setsize * SETelemsize;
   if (size>0 && size <= qh->qhmem.LASTsize) {
     qh_memalloc_(qh, size, freelistp, set, setT);
 #ifndef qh_NOmem
     sizereceived= qh->qhmem.sizetable[ qh->qhmem.indextable[size]];
     if (sizereceived > size)
       setsize += (sizereceived - size)/SETelemsize;
 #endif
   }else
     set= (setT*)qh_memalloc(qh, size);
   set->maxsize= setsize;
   set->e[setsize].i= 1;
   set->e[0].p= NULL;
   return(set);
 } /* setnew */
 
 
 /*---------------------------------
 
   qh_setnew_delnthsorted(qh, set, size, nth, prepend )
     creates a sorted set not containing nth element
     if prepend, the first prepend elements are undefined
 
   notes:
     set must be defined
     checks nth
     see also: setdelnthsorted
 
   design:
     create new set
     setup pointers and allocate room for prepend'ed entries
     append head of old set to new set
     append tail of old set to new set
 */
 setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend) {
   setT *newset;
   void **oldp, **newp;
   int tailsize= size - nth -1, newsize;
 
   if (tailsize < 0) {
     qh_fprintf(qh, qh->qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
     qh_setprint(qh, qh->qhmem.ferr, "", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   newsize= size-1 + prepend;
   newset= qh_setnew(qh, newsize);
   newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
   oldp= SETaddr_(set, void);
   newp= SETaddr_(newset, void) + prepend;
   switch (nth) {
   case 0:
     break;
   case 1:
     *(newp++)= *oldp++;
     break;
   case 2:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 3:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 4:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   default:
     memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
     newp += nth;
     oldp += nth;
     break;
   }
   oldp++;
   switch (tailsize) {
   case 0:
     break;
   case 1:
     *(newp++)= *oldp++;
     break;
   case 2:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 3:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   case 4:
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     *(newp++)= *oldp++;
     break;
   default:
     memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
     newp += tailsize;
   }
   *newp= NULL;
   return(newset);
 } /* setnew_delnthsorted */
 
 
 /*---------------------------------
 
   qh_setprint(qh, fp, string, set )
     print set elements to fp with identifying string
 
   notes:
     never errors
 */
 void qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set) {
   int size, k;
 
   if (!set)
     qh_fprintf(qh, fp, 9346, "%s set is null\n", string);
   else {
     SETreturnsize_(set, size);
     qh_fprintf(qh, fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
              string, set, set->maxsize, size);
     if (size > set->maxsize)
       size= set->maxsize+1;
     for (k=0; k < size; k++)
       qh_fprintf(qh, fp, 9348, " %p", set->e[k].p);
     qh_fprintf(qh, fp, 9349, "\n");
   }
 } /* setprint */
 
 /*---------------------------------
 
   qh_setreplace(qh, set, oldelem, newelem )
     replaces oldelem in set with newelem
 
   notes:
     errors if oldelem not in the set
     newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
 
   design:
     find oldelem
     replace with newelem
 */
 void qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem) {
   void **elemp;
 
   elemp= SETaddr_(set, void);
   while (*elemp != oldelem && *elemp)
     elemp++;
   if (*elemp)
     *elemp= newelem;
   else {
     qh_fprintf(qh, qh->qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
        oldelem);
     qh_setprint(qh, qh->qhmem.ferr, "", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
 } /* setreplace */
 
 
 /*---------------------------------
 
   qh_setsize(qh, set )
     returns the size of a set
 
   notes:
     errors if set's maxsize is incorrect
     same as SETreturnsize_(set)
     same code for qh_setsize [qset_r.c] and QhullSetBase::count
 
   design:
     determine actual size of set from maxsize
 */
 int qh_setsize(qhT *qh, setT *set) {
   int size;
   setelemT *sizep;
 
   if (!set)
     return(0);
   sizep= SETsizeaddr_(set);
   if ((size= sizep->i)) {
     size--;
     if (size > set->maxsize) {
       qh_fprintf(qh, qh->qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
                size, set->maxsize);
       qh_setprint(qh, qh->qhmem.ferr, "set: ", set);
       qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
     }
   }else
     size= set->maxsize;
   return size;
 } /* setsize */
 
 /*---------------------------------
 
   qh_settemp(qh, setsize )
     return a stacked, temporary set of upto setsize elements
 
   notes:
     use settempfree or settempfree_all to release from qh->qhmem.tempstack
     see also qh_setnew
 
   design:
     allocate set
     append to qh->qhmem.tempstack
 
 */
 setT *qh_settemp(qhT *qh, int setsize) {
   setT *newset;
 
   newset= qh_setnew(qh, setsize);
   qh_setappend(qh, &qh->qhmem.tempstack, newset);
   if (qh->qhmem.IStracing >= 5)
     qh_fprintf(qh, qh->qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
        newset, newset->maxsize, qh_setsize(qh, qh->qhmem.tempstack));
   return newset;
 } /* settemp */
 
 /*---------------------------------
 
   qh_settempfree(qh, set )
     free temporary set at top of qh->qhmem.tempstack
 
   notes:
     nop if set is NULL
     errors if set not from previous   qh_settemp
 
   to locate errors:
     use 'T2' to find source and then find mis-matching qh_settemp
 
   design:
     check top of qh->qhmem.tempstack
     free it
 */
 void qh_settempfree(qhT *qh, setT **set) {
   setT *stackedset;
 
   if (!*set)
     return;
   stackedset= qh_settemppop(qh);
   if (stackedset != *set) {
     qh_settemppush(qh, stackedset);
     qh_fprintf(qh, qh->qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
              *set, qh_setsize(qh, *set), qh_setsize(qh, qh->qhmem.tempstack)+1,
              stackedset, qh_setsize(qh, stackedset));
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   qh_setfree(qh, set);
 } /* settempfree */
 
 /*---------------------------------
 
   qh_settempfree_all(qh)
     free all temporary sets in qh->qhmem.tempstack
 
   design:
     for each set in tempstack
       free set
     free qh->qhmem.tempstack
 */
 void qh_settempfree_all(qhT *qh) {
   setT *set, **setp;
 
   FOREACHset_(qh->qhmem.tempstack)
     qh_setfree(qh, &set);
   qh_setfree(qh, &qh->qhmem.tempstack);
 } /* settempfree_all */
 
 /*---------------------------------
 
   qh_settemppop(qh)
     pop and return temporary set from qh->qhmem.tempstack
 
   notes:
     the returned set is permanent
 
   design:
     pop and check top of qh->qhmem.tempstack
 */
 setT *qh_settemppop(qhT *qh) {
   setT *stackedset;
 
   stackedset= (setT*)qh_setdellast(qh->qhmem.tempstack);
   if (!stackedset) {
     qh_fprintf(qh, qh->qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   if (qh->qhmem.IStracing >= 5)
     qh_fprintf(qh, qh->qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
        qh_setsize(qh, qh->qhmem.tempstack)+1, stackedset, qh_setsize(qh, stackedset));
   return stackedset;
 } /* settemppop */
 
 /*---------------------------------
 
   qh_settemppush(qh, set )
     push temporary set unto qh->qhmem.tempstack (makes it temporary)
 
   notes:
     duplicates settemp() for tracing
 
   design:
     append set to tempstack
 */
 void qh_settemppush(qhT *qh, setT *set) {
     if (!set) {
         fprintf (qh->qhmem.ferr, "qhull error (qh_settemppush): can not push a NULL temp\n");
         qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
     }
   qh_setappend(qh, &qh->qhmem.tempstack, set);
   if (qh->qhmem.IStracing >= 5)
     qh_fprintf(qh, qh->qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
       qh_setsize(qh, qh->qhmem.tempstack), set, qh_setsize(qh, set));
 } /* settemppush */
 
 
 /*---------------------------------
 
   qh_settruncate(qh, set, size )
     truncate set to size elements
 
   notes:
     set must be defined
 
   see:
     SETtruncate_
 
   design:
     check size
     update actual size of set
 */
 void qh_settruncate(qhT *qh, setT *set, int size) {
 
   if (size < 0 || size > set->maxsize) {
     qh_fprintf(qh, qh->qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
     qh_setprint(qh, qh->qhmem.ferr, "", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   set->e[set->maxsize].i= size+1;   /* maybe overwritten */
   set->e[size].p= NULL;
 } /* settruncate */
 
 /*---------------------------------
 
   qh_setunique(qh, set, elem )
     add elem to unsorted set unless it is already in set
 
   notes:
     returns 1 if it is appended
 
   design:
     if elem not in set
       append elem to set
 */
 int qh_setunique(qhT *qh, setT **set, void *elem) {
 
   if (!qh_setin(*set, elem)) {
     qh_setappend(qh, set, elem);
     return 1;
   }
   return 0;
 } /* setunique */
 
 /*---------------------------------
 
   qh_setzero(qh, set, index, size )
     zero elements from index on
     set actual size of set to size
 
   notes:
     set must be defined
     the set becomes an indexed set (can not use FOREACH...)
 
   see also:
     qh_settruncate
 
   design:
     check index and size
     update actual size
     zero elements starting at e[index]
 */
 void qh_setzero(qhT *qh, setT *set, int idx, int size) {
   int count;
 
   if (idx < 0 || idx >= size || size > set->maxsize) {
     qh_fprintf(qh, qh->qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
     qh_setprint(qh, qh->qhmem.ferr, "", set);
     qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
   }
   set->e[set->maxsize].i=  size+1;  /* may be overwritten */
   count= size - idx + 1;   /* +1 for NULL terminator */
   memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
 } /* setzero */
 
 
diff --git a/src/libqhullr/qset_r.h b/src/libqhullr/qset_r.h
index 5290b94..2a1556d 100644
--- a/src/libqhullr/qset_r.h
+++ b/src/libqhullr/qset_r.h
@@ -1,498 +1,498 @@
 /*
  ---------------------------------
 
    qset_r.h
      header file for qset_r.c that implements set
 
    see qh-set.htm and qset_r.c
 
    only uses mem_r.c, malloc/free
 
    for error handling, writes message and calls
       qh_errexit(qhT *qh, qhmem_ERRqhull, NULL, NULL);
 
    set operations satisfy the following properties:
     - sets have a max size, the actual size (if different) is stored at the end
     - every set is NULL terminated
     - sets may be sorted or unsorted, the caller must distinguish this
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/qset_r.h#8 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/qset_r.h#9 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFset
 #define qhDEFset 1
 
 #include 
 
 /*================= -structures- ===============*/
 
 #ifndef DEFsetT
 #define DEFsetT 1
 typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
 #endif
 
 #ifndef DEFqhT
 #define DEFqhT 1
 typedef struct qhT qhT;          /* defined in libqhull_r.h */
 #endif
 
 #ifndef DEFcountT
 #define DEFcountT 1
 typedef int countT;          /* defined in user_r.h */
 #endif
 
 /*------------------------------------------
 
 setT
   a set or list of pointers with maximum size and actual size.
 
 variations:
   unsorted, unique   -- a list of unique pointers with NULL terminator
                            user guarantees uniqueness
   sorted             -- a sorted list of unique pointers with NULL terminator
                            qset_r.c guarantees uniqueness
   unsorted           -- a list of pointers terminated with NULL
   indexed            -- an array of pointers with NULL elements
 
 structure for set of n elements:
 
         --------------
         |  maxsize
         --------------
         |  e[0] - a pointer, may be NULL for indexed sets
         --------------
         |  e[1]
 
         --------------
         |  ...
         --------------
         |  e[n-1]
         --------------
         |  e[n] = NULL
         --------------
         |  ...
         --------------
         |  e[maxsize] - n+1 or NULL (determines actual size of set)
         --------------
 
 */
 
 /*-- setelemT -- internal type to allow both pointers and indices
 */
 typedef union setelemT setelemT;
 union setelemT {
   void    *p;
   countT   i;         /* integer used for e[maxSize] */
 };
 
 struct setT {
   countT maxsize;          /* maximum number of elements (except NULL) */
   setelemT e[1];        /* array of pointers, tail is NULL */
                         /* last slot (unless NULL) is actual size+1
                            e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
                         /* this may generate a warning since e[] contains
                            maxsize elements */
 };
 
 /*=========== -constants- =========================*/
 
 /*-------------------------------------
 
   SETelemsize
     size of a set element in bytes
 */
 #define SETelemsize ((int)sizeof(setelemT))
 
 
 /*=========== -macros- =========================*/
 
 /*-------------------------------------
 
    FOREACHsetelement_(type, set, variable)
      define FOREACH iterator
 
    declare:
      assumes *variable and **variablep are declared
      no space in "variable)" [DEC Alpha cc compiler]
 
    each iteration:
      variable is set element
      variablep is one beyond variable.
 
    to repeat an element:
      variablep--; / *repeat* /
 
    at exit:
      variable is NULL at end of loop
 
    example:
      #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
 
    notes:
      use FOREACHsetelement_i_() if need index or include NULLs
 
    WARNING:
      nested loops can't use the same variable (define another FOREACH)
 
      needs braces if nested inside another FOREACH
      this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
 */
 #define FOREACHsetelement_(type, set, variable) \
         if (((variable= NULL), set)) for (\
           variable##p= (type **)&((set)->e[0].p); \
           (variable= *variable##p++);)
 
 /*------------------------------------------
 
    FOREACHsetelement_i_(qh, type, set, variable)
      define indexed FOREACH iterator
 
    declare:
      type *variable, variable_n, variable_i;
 
    each iteration:
      variable is set element, may be NULL
      variable_i is index, variable_n is qh_setsize()
 
    to repeat an element:
      variable_i--; variable_n-- repeats for deleted element
 
    at exit:
      variable==NULL and variable_i==variable_n
 
    example:
      #define FOREACHfacet_i_( qh, facets ) FOREACHsetelement_i_( qh, facetT, facets, facet )
 
    WARNING:
      nested loops can't use the same variable (define another FOREACH)
 
      needs braces if nested inside another FOREACH
      this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
 */
 #define FOREACHsetelement_i_(qh, type, set, variable) \
         if (((variable= NULL), set)) for (\
           variable##_i= 0, variable= (type *)((set)->e[0].p), \
                    variable##_n= qh_setsize(qh, set);\
           variable##_i < variable##_n;\
           variable= (type *)((set)->e[++variable##_i].p) )
 
 /*----------------------------------------
 
    FOREACHsetelementreverse_(qh, type, set, variable)-
      define FOREACH iterator in reverse order
 
    declare:
      assumes *variable and **variablep are declared
      also declare 'countT variabletemp'
 
    each iteration:
      variable is set element
 
    to repeat an element:
      variabletemp++; / *repeat* /
 
    at exit:
      variable is NULL
 
    example:
      #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
 
    notes:
      use FOREACHsetelementreverse12_() to reverse first two elements
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHsetelementreverse_(qh, type, set, variable) \
         if (((variable= NULL), set)) for (\
            variable##temp= qh_setsize(qh, set)-1, variable= qh_setlast(qh, set);\
            variable; variable= \
            ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
 
 /*-------------------------------------
 
    FOREACHsetelementreverse12_(type, set, variable)-
      define FOREACH iterator with e[1] and e[0] reversed
 
    declare:
      assumes *variable and **variablep are declared
 
    each iteration:
      variable is set element
      variablep is one after variable.
 
    to repeat an element:
      variablep--; / *repeat* /
 
    at exit:
      variable is NULL at end of loop
 
    example
      #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
 
    notes:
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHsetelementreverse12_(type, set, variable) \
         if (((variable= NULL), set)) for (\
           variable##p= (type **)&((set)->e[1].p); \
           (variable= *variable##p); \
           variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
               (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
 
 /*-------------------------------------
 
    FOREACHelem_( set )-
      iterate elements in a set
 
    declare:
      void *elem, *elemp;
 
    each iteration:
      elem is set element
      elemp is one beyond
 
    to repeat an element:
      elemp--; / *repeat* /
 
    at exit:
      elem == NULL at end of loop
 
    example:
      FOREACHelem_(set) {
 
    notes:
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
 
 /*-------------------------------------
 
    FOREACHset_( set )-
      iterate a set of sets
 
    declare:
      setT *set, **setp;
 
    each iteration:
      set is set element
      setp is one beyond
 
    to repeat an element:
      setp--; / *repeat* /
 
    at exit:
      set == NULL at end of loop
 
    example
      FOREACHset_(sets) {
 
    notes:
      WARNING: needs braces if nested inside another FOREACH
 */
 #define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
 
 /*-------------------------------------------
 
    SETindex_( set, elem )
      return index of elem in set
 
    notes:
      for use with FOREACH iteration
      WARN64 -- Maximum set size is 2G
 
    example:
      i= SETindex_(ridges, ridge)
 */
 #define SETindex_(set, elem) ((countT)((void **)elem##p - (void **)&(set)->e[1].p))
 
 /*-----------------------------------------
 
    SETref_( elem )
      l.h.s. for modifying the current element in a FOREACH iteration
 
    example:
      SETref_(ridge)= anotherridge;
 */
 #define SETref_(elem) (elem##p[-1])
 
 /*-----------------------------------------
 
    SETelem_(set, n)
      return the n'th element of set
 
    notes:
       assumes that n is valid [0..size] and that set is defined
       use SETelemt_() for type cast
 */
 #define SETelem_(set, n)           ((set)->e[n].p)
 
 /*-----------------------------------------
 
    SETelemt_(set, n, type)
      return the n'th element of set as a type
 
    notes:
       assumes that n is valid [0..size] and that set is defined
 */
 #define SETelemt_(set, n, type)    ((type*)((set)->e[n].p))
 
 /*-----------------------------------------
 
    SETelemaddr_(set, n, type)
      return address of the n'th element of a set
 
    notes:
       assumes that n is valid [0..size] and set is defined
 */
 #define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
 
 /*-----------------------------------------
 
    SETfirst_(set)
      return first element of set
 
 */
 #define SETfirst_(set)             ((set)->e[0].p)
 
 /*-----------------------------------------
 
    SETfirstt_(set, type)
      return first element of set as a type
 
 */
 #define SETfirstt_(set, type)      ((type*)((set)->e[0].p))
 
 /*-----------------------------------------
 
    SETsecond_(set)
      return second element of set
 
 */
 #define SETsecond_(set)            ((set)->e[1].p)
 
 /*-----------------------------------------
 
    SETsecondt_(set, type)
      return second element of set as a type
 */
 #define SETsecondt_(set, type)     ((type*)((set)->e[1].p))
 
 /*-----------------------------------------
 
    SETaddr_(set, type)
        return address of set's elements
 */
 #define SETaddr_(set,type)         ((type **)(&((set)->e[0].p)))
 
 /*-----------------------------------------
 
    SETreturnsize_(set, size)
      return size of a set
 
    notes:
       set must be defined
       use qh_setsize(qhT *qh, set) unless speed is critical
 */
 #define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
 
 /*-----------------------------------------
 
    SETempty_(set)
      return true(1) if set is empty
 
    notes:
       set may be NULL
 */
 #define SETempty_(set)            (!set || (SETfirst_(set) ? 0 : 1))
 
 /*---------------------------------
 
   SETsizeaddr_(set)
     return pointer to 'actual size+1' of set (set CANNOT be NULL!!)
     Its type is setelemT* for strict aliasing
     All SETelemaddr_ must be cast to setelemT
 
 
   notes:
     *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
 */
 #define SETsizeaddr_(set) (&((set)->e[(set)->maxsize]))
 
 /*-----------------------------------------
 
    SETtruncate_(set, size)
      truncate set to size
 
    see:
      qh_settruncate()
 
 */
 #define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
       set->e[size].p= NULL;}
 
 /*======= prototypes in alphabetical order ============*/
 
 void  qh_setaddsorted(qhT *qh, setT **setp, void *elem);
 void  qh_setaddnth(qhT *qh, setT **setp, countT nth, void *newelem);
 void  qh_setappend(qhT *qh, setT **setp, void *elem);
 void  qh_setappend_set(qhT *qh, setT **setp, setT *setA);
 void  qh_setappend2ndlast(qhT *qh, setT **setp, void *elem);
 void  qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned id);
 void  qh_setcompact(qhT *qh, setT *set);
 setT *qh_setcopy(qhT *qh, setT *set, countT extra);
 void *qh_setdel(setT *set, void *elem);
 void *qh_setdellast(setT *set);
 void *qh_setdelnth(qhT *qh, setT *set, countT nth);
 void *qh_setdelnthsorted(qhT *qh, setT *set, countT nth);
 void *qh_setdelsorted(setT *set, void *newelem);
 setT *qh_setduplicate(qhT *qh, setT *set, int elemsize);
 void **qh_setendpointer(setT *set);
 int   qh_setequal(setT *setA, setT *setB);
 int   qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB);
 int   qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB);
 void  qh_setfree(qhT *qh, setT **set);
 void  qh_setfree2(qhT *qh, setT **setp, int elemsize);
 void  qh_setfreelong(qhT *qh, setT **set);
 int   qh_setin(setT *set, void *setelem);
 countT qh_setindex(setT *set, void *setelem);
 void  qh_setlarger(qhT *qh, setT **setp);
 void *qh_setlast(setT *set);
 setT *qh_setnew(qhT *qh, countT size);
 setT *qh_setnew_delnthsorted(qhT *qh, setT *set, countT size, countT nth, countT prepend);
 void  qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set);
 void  qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem);
 countT qh_setsize(qhT *qh, setT *set);
 setT *qh_settemp(qhT *qh, countT setsize);
 void  qh_settempfree(qhT *qh, setT **set);
 void  qh_settempfree_all(qhT *qh);
 setT *qh_settemppop(qhT *qh);
 void  qh_settemppush(qhT *qh, setT *set);
 void  qh_settruncate(qhT *qh, setT *set, countT size);
 int   qh_setunique(qhT *qh, setT **set, void *elem);
 void  qh_setzero(qhT *qh, setT *set, countT idx, countT size);
 
 
 #endif /* qhDEFset */
diff --git a/src/libqhullr/random_r.h b/src/libqhullr/random_r.h
index a1557be..f5ee920 100644
--- a/src/libqhullr/random_r.h
+++ b/src/libqhullr/random_r.h
@@ -1,34 +1,34 @@
 /*
  ---------------------------------
 
   random.h
     header file for random routines
 
    see qh-geom.htm and random_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/random_r.h#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/random_r.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #ifndef qhDEFrandom
 #define qhDEFrandom 1
 
 #include "libqhull_r.h"
 
 /*============= prototypes in alphabetical order ======= */
 
 
 int     qh_argv_to_command(int argc, char *argv[], char* command, int max_size);
 int     qh_argv_to_command_size(int argc, char *argv[]);
 int     qh_rand(qhT *qh);
 void    qh_srand(qhT *qh, int seed);
 realT   qh_randomfactor(qhT *qh, realT scale, realT offset);
 void    qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **row);
 int     qh_strtol(const char *s, char **endp);
 double  qh_strtod(const char *s, char **endp);
 
 #endif /* qhDEFrandom */
 
 
 
diff --git a/src/libqhullr/stat_r.c b/src/libqhullr/stat_r.c
index 0e563df..7ffb072 100644
--- a/src/libqhullr/stat_r.c
+++ b/src/libqhullr/stat_r.c
@@ -1,683 +1,683 @@
 /*
  ---------------------------------
 
    stat_r.c
    contains all statistics that are collected for qhull
 
    see qh-stat.htm and stat_r.h
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/stat_r.c#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/stat_r.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "qhull_ra.h"
 
 /*========== functions in alphabetic order ================*/
 
 /*---------------------------------
 
   qh_allstatA()
     define statistics in groups of 20
 
   notes:
     (otherwise, 'gcc -O2' uses too much memory)
     uses qhstat.next 
 */
 void qh_allstatA(qhT *qh) {
 
    /* zdef_(type,name,doc,average) */
   zzdef_(zdoc, Zdoc2, "precision statistics", -1);
   zdef_(zinc, Znewvertex, NULL, -1);
   zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet(!0s)", Znewvertex);
   zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
   zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
   zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
   zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
 
   qh->qhstat.precision= qh->qhstat.next;  /* call qh_precision for each of these */
   zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);
   zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
   zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
   zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
   zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
   zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
   zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);
   zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
   zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
   zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
   zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);
 }
 void qh_allstatB(qhT *qh) {
   zzdef_(zdoc, Zdoc1, "summary information", -1);
   zdef_(zinc, Zvertices, "number of vertices in output", -1);
   zdef_(zinc, Znumfacets, "number of facets in output", -1);
   zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
   zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);
   zdef_(zinc, Znumridges, "number of ridges in output", -1);
   zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
   zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
   zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
   zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
   zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
   zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
   zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
   zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
   zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
   zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
   zzdef_(zinc, Zsetplane, "facets created altogether", -1);
   zdef_(zinc, Ztotridges, "ridges created altogether", -1);
   zdef_(zinc, Zpostfacets, "facets before post merge", -1);
   zdef_(zadd, Znummergetot, "average merges per facet(at most 511)", Znumfacets);
   zdef_(zmax, Znummergemax, "  maximum merges for a facet(at most 511)", -1);
   zdef_(zinc, Zangle, NULL, -1);
   zdef_(wadd, Wangle, "average angle(cosine) of facet normals for all ridges", Zangle);
   zdef_(wmax, Wanglemax, "  maximum angle(cosine) of facet normals across a ridge", -1);
   zdef_(wmin, Wanglemin, "  minimum angle(cosine) of facet normals across a ridge", -1);
   zdef_(wadd, Wareatot, "total area of facets", -1);
   zdef_(wmax, Wareamax, "  maximum facet area", -1);
   zdef_(wmin, Wareamin, "  minimum facet area", -1);
 }
 void qh_allstatC(qhT *qh) {
   zdef_(zdoc, Zdoc9, "build hull statistics", -1);
   zzdef_(zinc, Zprocessed, "points processed", -1);
   zzdef_(zinc, Zretry, "retries due to precision problems", -1);
   zdef_(wmax, Wretrymax, "  max. random joggle", -1);
   zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
   zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
   zdef_(zinc, Zinsidevisible, "  ave. visible facets without an horizon neighbor", Zprocessed);
   zdef_(zadd, Zvisfacettot,  "  ave. facets deleted per iteration", Zprocessed);
   zdef_(zmax, Zvisfacetmax,  "    maximum", -1);
   zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
   zdef_(zmax, Zvisvertexmax, "    maximum", -1);
   zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
   zdef_(zadd, Znewfacettot,  "ave. new or merged facets per iteration", Zprocessed);
   zdef_(zmax, Znewfacetmax,  "    maximum(includes initial simplex)", -1);
   zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
   zdef_(wadd, Wnewbalance2, "  standard deviation", -1);
   zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
   zdef_(wadd, Wpbalance2, "  standard deviation", -1);
   zdef_(zinc, Zpbalance, "  number of trials", -1);
   zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
   zdef_(zinc, Zdetsimplex, "determinants computed(area & initial hull)", -1);
   zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);
   zdef_(zinc, Znotmax, "points ignored(!above max_outside)", -1);
   zdef_(zinc, Znotgood, "points ignored(!above a good facet)", -1);
   zdef_(zinc, Znotgoodnew, "points ignored(didn't create a good new facet)", -1);
   zdef_(zinc, Zgoodfacet, "good facets found", -1);
   zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
   zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
   zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
   zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
 }
 void qh_allstatD(qhT *qh) {
   zdef_(zinc, Zvisit, "resets of visit_id", -1);
   zdef_(zinc, Zvvisit, "  resets of vertex_visit", -1);
   zdef_(zmax, Zvisit2max, "  max visit_id/2", -1);
   zdef_(zmax, Zvvisit2max, "  max vertex_visit/2", -1);
 
   zdef_(zdoc, Zdoc4, "partitioning statistics(see previous for outer planes)", -1);
   zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
   zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
   zdef_(zinc, Zfindbest, "calls to findbest", -1);
   zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
   zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
   zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
   zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
   zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
   zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
   zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
   zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
   zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
   zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
   zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
   zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
   zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);
   zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
   zdef_(zinc, Zpartflip, "  repartitioned coplanar points for flipped orientation", -1);
 }
 void qh_allstatE(qhT *qh) {
   zdef_(zinc, Zpartinside, "inside points", -1);
   zdef_(zinc, Zpartnear, "  inside points kept with a facet", -1);
   zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
   zdef_(zinc, Zbestlower, "calls to findbestlower", -1);
   zdef_(zinc, Zbestlowerv, "  with search of vertex neighbors", -1);
   zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
   zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
   zdef_(zinc, Ztotpartition, "partitions of a point", -1);
   zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
   zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
   zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
   zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
   zdef_(zinc, Zdistio, "distance tests for output", -1);
   zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
   zdef_(zinc, Zdistplane, "total number of distance tests", -1);
   zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
   zzdef_(zinc, Zpartcoplanar, "   distance tests for these partitions", -1);
   zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
 }
 void qh_allstatE2(qhT *qh) {
   zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
   zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
   zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
   zdef_(zinc, Zhashridge, "total lookups of subridges(duplicates and boundary)", -1);
   zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
   zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
   zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);
 
   zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
   zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
   zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
   zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
   zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
   zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);
   zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
   zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);
   zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
 }
 void qh_allstatF(qhT *qh) {
   zdef_(zdoc, Zdoc7, "statistics for merging", -1);
   zdef_(zinc, Zpremergetot, "merge iterations", -1);
   zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
   zdef_(zadd, Zmergeinitmax, "  maximum", -1);
   zdef_(zadd, Zmergesettot, "  ave. additional non-convex ridges per iteration", Zpremergetot);
   zdef_(zadd, Zmergesetmax, "  maximum additional in one pass", -1);
   zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
   zdef_(zadd, Zmergesettot2, "  additional non-convex ridges", -1);
   zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet(w/roundoff)", -1);
   zdef_(wmin, Wminvertex, "max distance of merged vertex below facet(or roundoff)", -1);
   zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);
   zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);
   zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);
   zdef_(zinc, Zmergesimplex, "merged a simplex", -1);
   zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);
   zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);
   zzdef_(zadd, Zcyclefacettot, "  ave. facets per cycle", Zcyclehorizon);
   zdef_(zmax, Zcyclefacetmax, "  max. facets", -1);
   zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
   zdef_(zinc, Zmergenew, "new facets merged", -1);
   zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
   zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
   zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);
   zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
   zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
   zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);
   zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);
 }
 void qh_allstatG(qhT *qh) {
   zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
   zdef_(wadd, Wacoplanartot, "  average merge distance", Zacoplanar);
   zdef_(wmax, Wacoplanarmax, "  maximum merge distance", -1);
   zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
   zdef_(wadd, Wcoplanartot, "  average merge distance", Zcoplanar);
   zdef_(wmax, Wcoplanarmax, "  maximum merge distance", -1);
   zdef_(zinc, Zconcave, "merges due to concave facets", -1);
   zdef_(wadd, Wconcavetot, "  average merge distance", Zconcave);
   zdef_(wmax, Wconcavemax, "  maximum merge distance", -1);
   zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
   zdef_(wadd, Wavoidoldtot, "  average merge distance", Zavoidold);
   zdef_(wmax, Wavoidoldmax, "  maximum merge distance", -1);
   zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
   zdef_(wadd, Wdegentot, "  average merge distance", Zdegen);
   zdef_(wmax, Wdegenmax, "  maximum merge distance", -1);
   zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
   zdef_(wadd, Wflippedtot, "  average merge distance", Zflipped);
   zdef_(wmax, Wflippedmax, "  maximum merge distance", -1);
   zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);
   zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
   zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
 }
 void qh_allstatH(qhT *qh) {
   zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);
   zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
   zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
   zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
   zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
   zdef_(zinc, Zdupridge, "  duplicate ridges detected", -1);
   zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
   zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
   zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);
   zdef_(zinc, Zdelfacetdup, "  facets deleted because of no neighbors", -1);
   zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
   zdef_(zinc, Zremvertexdel, "  deleted", -1);
   zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
   zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
   zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
   zdef_(zadd, Zintersecttot, "   ave. number found per vertex", Zintersect);
   zdef_(zmax, Zintersectmax, "   max. found for a vertex", -1);
   zdef_(zinc, Zvertexridge, NULL, -1);
   zdef_(zadd, Zvertexridgetot, "  ave. number of ridges per tested vertex", Zvertexridge);
   zdef_(zmax, Zvertexridgemax, "  max. number of ridges per tested vertex", -1);
 
   zdef_(zdoc, Zdoc10, "memory usage statistics(in bytes)", -1);
   zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
   zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
   zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1);
   zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
 } /* allstat */
 
 void qh_allstatI(qhT *qh) {
   qh->qhstat.vridges= qh->qhstat.next;
   zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
   zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
   zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
   zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
   zzdef_(zinc, Zridgemid, "bounded ridges", -1);
   zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
   zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
   zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
   zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
   zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
   zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
   zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
   zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);
 
   zdef_(zdoc, Zdoc12, "Triangulation statistics(Qt)", -1);
   zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
   zdef_(zadd, Ztricoplanartot, "  ave. new facets created(may be deleted)", Ztricoplanar);
   zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
   zdef_(zinc, Ztrinull, "null new facets deleted(duplicated vertex)", -1);
   zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted(same vertices)", -1);
   zdef_(zinc, Ztridegen, "degenerate new facets in output(same ridge)", -1);
 } /* allstat */
 
 /*---------------------------------
 
   qh_allstatistics()
     reset printed flag for all statistics
 */
 void qh_allstatistics(qhT *qh) {
   int i;
 
   for(i=ZEND; i--; )
     qh->qhstat.printed[i]= False;
 } /* allstatistics */
 
 #if qh_KEEPstatistics
 /*---------------------------------
 
   qh_collectstatistics()
     collect statistics for qh.facet_list
 
 */
 void qh_collectstatistics(qhT *qh) {
   facetT *facet, *neighbor, **neighborp;
   vertexT *vertex, **vertexp;
   realT dotproduct, dist;
   int sizneighbors, sizridges, sizvertices, i;
 
   qh->old_randomdist= qh->RANDOMdist;
   qh->RANDOMdist= False;
   zval_(Zmempoints)= qh->num_points * qh->normal_size +
                              sizeof(qhT) + sizeof(qhstatT);
   zval_(Zmemfacets)= 0;
   zval_(Zmemridges)= 0;
   zval_(Zmemvertices)= 0;
   zval_(Zangle)= 0;
   wval_(Wangle)= 0.0;
   zval_(Znumridges)= 0;
   zval_(Znumfacets)= 0;
   zval_(Znumneighbors)= 0;
   zval_(Znumvertices)= 0;
   zval_(Znumvneighbors)= 0;
   zval_(Znummergetot)= 0;
   zval_(Znummergemax)= 0;
   zval_(Zvertices)= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
   if (qh->MERGING || qh->APPROXhull || qh->JOGGLEmax < REALmax/2)
     wmax_(Wmaxoutside, qh->max_outside);
   if (qh->MERGING)
     wmin_(Wminvertex, qh->min_vertex);
   FORALLfacets
     facet->seen= False;
   if (qh->DELAUNAY) {
     FORALLfacets {
       if (facet->upperdelaunay != qh->UPPERdelaunay)
         facet->seen= True; /* remove from angle statistics */
     }
   }
   FORALLfacets {
     if (facet->visible && qh->NEWfacets)
       continue;
     sizvertices= qh_setsize(qh, facet->vertices);
     sizneighbors= qh_setsize(qh, facet->neighbors);
     sizridges= qh_setsize(qh, facet->ridges);
     zinc_(Znumfacets);
     zadd_(Znumvertices, sizvertices);
     zmax_(Zmaxvertices, sizvertices);
     zadd_(Znumneighbors, sizneighbors);
     zmax_(Zmaxneighbors, sizneighbors);
     zadd_(Znummergetot, facet->nummerge);
     i= facet->nummerge; /* avoid warnings */
     zmax_(Znummergemax, i);
     if (!facet->simplicial) {
       if (sizvertices == qh->hull_dim) {
         zinc_(Znowsimplicial);
       }else {
         zinc_(Znonsimplicial);
       }
     }
     if (sizridges) {
       zadd_(Znumridges, sizridges);
       zmax_(Zmaxridges, sizridges);
     }
     zadd_(Zmemfacets, sizeof(facetT) + qh->normal_size + 2*sizeof(setT)
        + SETelemsize * (sizneighbors + sizvertices));
     if (facet->ridges) {
       zadd_(Zmemridges,
          sizeof(setT) + SETelemsize * sizridges + sizridges *
          (sizeof(ridgeT) + sizeof(setT) + SETelemsize * (qh->hull_dim-1))/2);
     }
     if (facet->outsideset)
       zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(qh, facet->outsideset));
     if (facet->coplanarset)
       zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(qh, facet->coplanarset));
     if (facet->seen) /* Delaunay upper envelope */
       continue;
     facet->seen= True;
     FOREACHneighbor_(facet) {
       if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
           || neighbor->seen || !facet->normal || !neighbor->normal)
         continue;
       dotproduct= qh_getangle(qh, facet->normal, neighbor->normal);
       zinc_(Zangle);
       wadd_(Wangle, dotproduct);
       wmax_(Wanglemax, dotproduct)
       wmin_(Wanglemin, dotproduct)
     }
     if (facet->normal) {
       FOREACHvertex_(facet->vertices) {
         zinc_(Zdiststat);
         qh_distplane(qh, vertex->point, facet, &dist);
         wmax_(Wvertexmax, dist);
         wmin_(Wvertexmin, dist);
       }
     }
   }
   FORALLvertices {
     if (vertex->deleted)
       continue;
     zadd_(Zmemvertices, sizeof(vertexT));
     if (vertex->neighbors) {
       sizneighbors= qh_setsize(qh, vertex->neighbors);
       zadd_(Znumvneighbors, sizneighbors);
       zmax_(Zmaxvneighbors, sizneighbors);
       zadd_(Zmemvertices, sizeof(vertexT) + SETelemsize * sizneighbors);
     }
   }
   qh->RANDOMdist= qh->old_randomdist;
 } /* collectstatistics */
 #endif /* qh_KEEPstatistics */
 
 /*---------------------------------
 
   qh_initstatistics(qh)
     initialize statistics
     Requires
 
   notes:
   NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr  
   On first call, only qhmem.ferr is defined.  qh_memalloc is not setup.  
   Also invoked by QhullQh().
 */
 void qh_initstatistics(qhT *qh) {
   int i;
   realT realx;
   int intx;
 
   qh->qhstat.next= 0;
   qh_allstatA(qh);
   qh_allstatB(qh);
   qh_allstatC(qh);
   qh_allstatD(qh);
   qh_allstatE(qh);
   qh_allstatE2(qh);
   qh_allstatF(qh);
   qh_allstatG(qh);
   qh_allstatH(qh);
   qh_allstatI(qh);
   if (qh->qhstat.next > (int)sizeof(qh->qhstat.id)) {
     qh_fprintf(qh, qh->qhmem.ferr, 6184, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\
       qhstat.next %d should be <= sizeof(qh->qhstat.id) %d\n", qh->qhstat.next, (int)sizeof(qh->qhstat.id));
 #if 0 /* for locating error, Znumridges should be duplicated */
     for(i=0; i < ZEND; i++) {
       int j;
       for(j=i+1; j < ZEND; j++) {
         if (qh->qhstat.id[i] == qh->qhstat.id[j]) {
           qh_fprintf(qh, qh->qhmem.ferr, 6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
               qh->qhstat.id[i], i, j);
         }
       }
     }
 #endif
     qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
   }
   qh->qhstat.init[zinc].i= 0;
   qh->qhstat.init[zadd].i= 0;
   qh->qhstat.init[zmin].i= INT_MAX;
   qh->qhstat.init[zmax].i= INT_MIN;
   qh->qhstat.init[wadd].r= 0;
   qh->qhstat.init[wmin].r= REALmax;
   qh->qhstat.init[wmax].r= -REALmax;
   for(i=0; i < ZEND; i++) {
     if (qh->qhstat.type[i] > ZTYPEreal) {
       realx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r;
       qh->qhstat.stats[i].r= realx;
     }else if (qh->qhstat.type[i] != zdoc) {
       intx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i;
       qh->qhstat.stats[i].i= intx;
     }
   }
 } /* initstatistics */
 
 /*---------------------------------
 
   qh_newstats(qh, )
     returns True if statistics for zdoc
 
   returns:
     next zdoc
 */
 boolT qh_newstats(qhT *qh, int idx, int *nextindex) {
   boolT isnew= False;
   int start, i;
 
   if (qh->qhstat.type[qh->qhstat.id[idx]] == zdoc)
     start= idx+1;
   else
     start= idx;
   for(i= start; i < qh->qhstat.next && qh->qhstat.type[qh->qhstat.id[i]] != zdoc; i++) {
     if (!qh_nostatistic(qh, qh->qhstat.id[i]) && !qh->qhstat.printed[qh->qhstat.id[i]])
         isnew= True;
   }
   *nextindex= i;
   return isnew;
 } /* newstats */
 
 /*---------------------------------
 
   qh_nostatistic(qh, index )
     true if no statistic to print
 */
 boolT qh_nostatistic(qhT *qh, int i) {
 
   if ((qh->qhstat.type[i] > ZTYPEreal
        &&qh->qhstat.stats[i].r == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r)
       || (qh->qhstat.type[i] < ZTYPEreal
           &&qh->qhstat.stats[i].i == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i))
     return True;
   return False;
 } /* nostatistic */
 
 #if qh_KEEPstatistics
 /*---------------------------------
 
   qh_printallstatistics(qh, fp, string )
     print all statistics with header 'string'
 */
 void qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {
 
   qh_allstatistics(qh);
   qh_collectstatistics(qh);
   qh_printstatistics(qh, fp, string);
   qh_memstatistics(qh, fp);
 }
 
 
 /*---------------------------------
 
   qh_printstatistics(qh, fp, string )
     print statistics to a file with header 'string'
     skips statistics with qhstat.printed[] (reset with qh_allstatistics)
 
   see:
     qh_printallstatistics()
 */
 void qh_printstatistics(qhT *qh, FILE *fp, const char *string) {
   int i, k;
   realT ave;
 
   if (qh->num_points != qh->num_vertices) {
     wval_(Wpbalance)= 0;
     wval_(Wpbalance2)= 0;
   }else
     wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
                                  wval_(Wpbalance2), &ave);
   wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
                                  wval_(Wnewbalance2), &ave);
   qh_fprintf(qh, fp, 9350, "\n\
 %s\n\
  qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh->rbox_command,
      qh->qhull_command, qh_version, qh->qhull_options);
   qh_fprintf(qh, fp, 9351, "\nprecision constants:\n\
  %6.2g max. abs. coordinate in the (transformed) input('Qbd:n')\n\
  %6.2g max. roundoff error for distance computation('En')\n\
  %6.2g max. roundoff error for angle computations\n\
  %6.2g min. distance for outside points ('Wn')\n\
  %6.2g min. distance for visible facets ('Vn')\n\
  %6.2g max. distance for coplanar facets ('Un')\n\
  %6.2g max. facet width for recomputing centrum and area\n\
 ",
   qh->MAXabs_coord, qh->DISTround, qh->ANGLEround, qh->MINoutside,
         qh->MINvisible, qh->MAXcoplanar, qh->WIDEfacet);
   if (qh->KEEPnearinside)
     qh_fprintf(qh, fp, 9352, "\
  %6.2g max. distance for near-inside points\n", qh->NEARinside);
   if (qh->premerge_cos < REALmax/2) qh_fprintf(qh, fp, 9353, "\
  %6.2g max. cosine for pre-merge angle\n", qh->premerge_cos);
   if (qh->PREmerge) qh_fprintf(qh, fp, 9354, "\
  %6.2g radius of pre-merge centrum\n", qh->premerge_centrum);
   if (qh->postmerge_cos < REALmax/2) qh_fprintf(qh, fp, 9355, "\
  %6.2g max. cosine for post-merge angle\n", qh->postmerge_cos);
   if (qh->POSTmerge) qh_fprintf(qh, fp, 9356, "\
  %6.2g radius of post-merge centrum\n", qh->postmerge_centrum);
   qh_fprintf(qh, fp, 9357, "\
  %6.2g max. distance for merging two simplicial facets\n\
  %6.2g max. roundoff error for arithmetic operations\n\
  %6.2g min. denominator for divisions\n\
   zero diagonal for Gauss: ", qh->ONEmerge, REALepsilon, qh->MINdenom);
   for(k=0; k < qh->hull_dim; k++)
     qh_fprintf(qh, fp, 9358, "%6.2e ", qh->NEARzero[k]);
   qh_fprintf(qh, fp, 9359, "\n\n");
   for(i=0 ; i < qh->qhstat.next; )
     qh_printstats(qh, fp, i, &i);
 } /* printstatistics */
 #endif /* qh_KEEPstatistics */
 
 /*---------------------------------
 
   qh_printstatlevel(qh, fp, id )
     print level information for a statistic
 
   notes:
     nop if id >= ZEND, printed, or same as initial value
 */
 void qh_printstatlevel(qhT *qh, FILE *fp, int id, int start) {
 #define NULLfield "       "
 
   if (id >= ZEND || qh->qhstat.printed[id])
     return;
   if (qh->qhstat.type[id] == zdoc) {
     qh_fprintf(qh, fp, 9360, "%s\n", qh->qhstat.doc[id]);
     return;
   }
   start= 0; /* not used */
   if (qh_nostatistic(qh, id) || !qh->qhstat.doc[id])
     return;
   qh->qhstat.printed[id]= True;
   if (qh->qhstat.count[id] != -1
       && qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i == 0)
     qh_fprintf(qh, fp, 9361, " *0 cnt*");
   else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] == -1)
     qh_fprintf(qh, fp, 9362, "%7.2g", qh->qhstat.stats[id].r);
   else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] != -1)
     qh_fprintf(qh, fp, 9363, "%7.2g", qh->qhstat.stats[id].r/ qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);
   else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] == -1)
     qh_fprintf(qh, fp, 9364, "%7d", qh->qhstat.stats[id].i);
   else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] != -1)
     qh_fprintf(qh, fp, 9365, "%7.3g", (realT) qh->qhstat.stats[id].i / qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);
   qh_fprintf(qh, fp, 9366, " %s\n", qh->qhstat.doc[id]);
 } /* printstatlevel */
 
 
 /*---------------------------------
 
   qh_printstats(qh, fp, index, nextindex )
     print statistics for a zdoc group
 
   returns:
     next zdoc if non-null
 */
 void qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex) {
   int j, nexti;
 
   if (qh_newstats(qh, idx, &nexti)) {
     qh_fprintf(qh, fp, 9367, "\n");
     for (j=idx; jqhstat.id[j], 0);
   }
   if (nextindex)
     *nextindex= nexti;
 } /* printstats */
 
 #if qh_KEEPstatistics
 
 /*---------------------------------
 
   qh_stddev(num, tot, tot2, ave )
     compute the standard deviation and average from statistics
 
     tot2 is the sum of the squares
   notes:
     computes r.m.s.:
       (x-ave)^2
       == x^2 - 2x tot/num +   (tot/num)^2
       == tot2 - 2 tot tot/num + tot tot/num
       == tot2 - tot ave
 */
 realT qh_stddev(int num, realT tot, realT tot2, realT *ave) {
   realT stddev;
 
   *ave= tot/num;
   stddev= sqrt(tot2/num - *ave * *ave);
   return stddev;
 } /* stddev */
 
 #endif /* qh_KEEPstatistics */
 
 #if !qh_KEEPstatistics
 void    qh_collectstatistics(qhT *qh) {}
 void    qh_printallstatistics(qhT *qh, FILE *fp, char *string) {};
 void    qh_printstatistics(qhT *qh, FILE *fp, char *string) {}
 #endif
 
diff --git a/src/libqhullr/stat_r.h b/src/libqhullr/stat_r.h
index f86f221..74d91ff 100644
--- a/src/libqhullr/stat_r.h
+++ b/src/libqhullr/stat_r.h
@@ -1,523 +1,523 @@
 /*
  ---------------------------------
 
    stat_r.h
      contains all statistics that are collected for qhull
 
    see qh-stat.htm and stat_r.c
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/libqhullr/stat_r.h#6 $$Change: 1797 $
-   $DateTime: 2014/12/15 17:23:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/libqhullr/stat_r.h#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 
    recompile qhull if you change this file
 
    Integer statistics are Z* while real statistics are W*.
 
    define MAYdebugx to call a routine at every statistic event
 
 */
 
 #ifndef qhDEFstat
 #define qhDEFstat 1
 
 /* Depends on realT.  Do not include libqhull_r to avoid circular dependency */
 
 #ifndef DEFqhT
 #define DEFqhT 1
 typedef struct qhT qhT;         /* Defined by libqhull_r.h */
 #endif
 
 #ifndef DEFqhstatT
 #define DEFqhstatT 1
 typedef struct qhstatT qhstatT; /* Defined here */
 #endif
 
 /*---------------------------------
 
   qh_KEEPstatistics
     0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
 */
 #ifndef qh_KEEPstatistics
 #define qh_KEEPstatistics 1
 #endif
 
 /*---------------------------------
 
   Zxxx for integers, Wxxx for reals
 
   notes:
     be sure that all statistics are defined in stat_r.c
       otherwise initialization may core dump
     can pick up all statistics by:
       grep '[zw].*_[(][ZW]' *.c >z.x
     remove trailers with query">-
     remove leaders with  query-replace-regexp [ ^I]+  (
 */
 #if qh_KEEPstatistics
 enum qh_statistics {     /* alphabetical after Z/W */
     Zacoplanar,
     Wacoplanarmax,
     Wacoplanartot,
     Zangle,
     Wangle,
     Wanglemax,
     Wanglemin,
     Zangletests,
     Wareatot,
     Wareamax,
     Wareamin,
     Zavoidold,
     Wavoidoldmax,
     Wavoidoldtot,
     Zback0,
     Zbestcentrum,
     Zbestdist,
     Zbestlower,
     Zbestlowerv,
     Zcentrumtests,
     Zcheckpart,
     Zcomputefurthest,
     Zconcave,
     Wconcavemax,
     Wconcavetot,
     Zconcaveridges,
     Zconcaveridge,
     Zcoplanar,
     Wcoplanarmax,
     Wcoplanartot,
     Zcoplanarangle,
     Zcoplanarcentrum,
     Zcoplanarhorizon,
     Zcoplanarinside,
     Zcoplanarpart,
     Zcoplanarridges,
     Wcpu,
     Zcyclefacetmax,
     Zcyclefacettot,
     Zcyclehorizon,
     Zcyclevertex,
     Zdegen,
     Wdegenmax,
     Wdegentot,
     Zdegenvertex,
     Zdelfacetdup,
     Zdelridge,
     Zdelvertextot,
     Zdelvertexmax,
     Zdetsimplex,
     Zdistcheck,
     Zdistconvex,
     Zdistgood,
     Zdistio,
     Zdistplane,
     Zdiststat,
     Zdistvertex,
     Zdistzero,
     Zdoc1,
     Zdoc2,
     Zdoc3,
     Zdoc4,
     Zdoc5,
     Zdoc6,
     Zdoc7,
     Zdoc8,
     Zdoc9,
     Zdoc10,
     Zdoc11,
     Zdoc12,
     Zdropdegen,
     Zdropneighbor,
     Zdupflip,
     Zduplicate,
     Wduplicatemax,
     Wduplicatetot,
     Zdupridge,
     Zdupsame,
     Zflipped,
     Wflippedmax,
     Wflippedtot,
     Zflippedfacets,
     Zfindbest,
     Zfindbestmax,
     Zfindbesttot,
     Zfindcoplanar,
     Zfindfail,
     Zfindhorizon,
     Zfindhorizonmax,
     Zfindhorizontot,
     Zfindjump,
     Zfindnew,
     Zfindnewmax,
     Zfindnewtot,
     Zfindnewjump,
     Zfindnewsharp,
     Zgauss0,
     Zgoodfacet,
     Zhashlookup,
     Zhashridge,
     Zhashridgetest,
     Zhashtests,
     Zinsidevisible,
     Zintersect,
     Zintersectfail,
     Zintersectmax,
     Zintersectnum,
     Zintersecttot,
     Zmaxneighbors,
     Wmaxout,
     Wmaxoutside,
     Zmaxridges,
     Zmaxvertex,
     Zmaxvertices,
     Zmaxvneighbors,
     Zmemfacets,
     Zmempoints,
     Zmemridges,
     Zmemvertices,
     Zmergeflipdup,
     Zmergehorizon,
     Zmergeinittot,
     Zmergeinitmax,
     Zmergeinittot2,
     Zmergeintohorizon,
     Zmergenew,
     Zmergesettot,
     Zmergesetmax,
     Zmergesettot2,
     Zmergesimplex,
     Zmergevertex,
     Wmindenom,
     Wminvertex,
     Zminnorm,
     Zmultiridge,
     Znearlysingular,
     Zneighbor,
     Wnewbalance,
     Wnewbalance2,
     Znewfacettot,
     Znewfacetmax,
     Znewvertex,
     Wnewvertex,
     Wnewvertexmax,
     Znoarea,
     Znonsimplicial,
     Znowsimplicial,
     Znotgood,
     Znotgoodnew,
     Znotmax,
     Znumfacets,
     Znummergemax,
     Znummergetot,
     Znumneighbors,
     Znumridges,
     Znumvertices,
     Znumvisibility,
     Znumvneighbors,
     Zonehorizon,
     Zpartangle,
     Zpartcoplanar,
     Zpartflip,
     Zparthorizon,
     Zpartinside,
     Zpartition,
     Zpartitionall,
     Zpartnear,
     Zpbalance,
     Wpbalance,
     Wpbalance2,
     Zpostfacets,
     Zpremergetot,
     Zprocessed,
     Zremvertex,
     Zremvertexdel,
     Zrenameall,
     Zrenamepinch,
     Zrenameshare,
     Zretry,
     Wretrymax,
     Zridge,
     Wridge,
     Wridgemax,
     Zridge0,
     Wridge0,
     Wridge0max,
     Zridgemid,
     Wridgemid,
     Wridgemidmax,
     Zridgeok,
     Wridgeok,
     Wridgeokmax,
     Zsearchpoints,
     Zsetplane,
     Ztestvneighbor,
     Ztotcheck,
     Ztothorizon,
     Ztotmerge,
     Ztotpartcoplanar,
     Ztotpartition,
     Ztotridges,
     Ztotvertices,
     Ztotvisible,
     Ztricoplanar,
     Ztricoplanarmax,
     Ztricoplanartot,
     Ztridegen,
     Ztrimirror,
     Ztrinull,
     Wvertexmax,
     Wvertexmin,
     Zvertexridge,
     Zvertexridgetot,
     Zvertexridgemax,
     Zvertices,
     Zvisfacettot,
     Zvisfacetmax,
     Zvisit,
     Zvisit2max,
     Zvisvertextot,
     Zvisvertexmax,
     Zvvisit,
     Zvvisit2max,
     Zwidefacet,
     Zwidevertices,
     ZEND};
 
 /*---------------------------------
 
   Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
 
   notes:
     be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
 */
 #else
 enum qh_statistics {     /* for zzdef etc. macros */
   Zback0,
   Zbestdist,
   Zcentrumtests,
   Zcheckpart,
   Zconcaveridges,
   Zcoplanarhorizon,
   Zcoplanarpart,
   Zcoplanarridges,
   Zcyclefacettot,
   Zcyclehorizon,
   Zdelvertextot,
   Zdistcheck,
   Zdistconvex,
   Zdistzero,
   Zdoc1,
   Zdoc2,
   Zdoc3,
   Zdoc11,
   Zflippedfacets,
   Zgauss0,
   Zminnorm,
   Zmultiridge,
   Znearlysingular,
   Wnewvertexmax,
   Znumvisibility,
   Zpartcoplanar,
   Zpartition,
   Zpartitionall,
   Zprocessed,
   Zretry,
   Zridge,
   Wridge,
   Wridgemax,
   Zridge0,
   Wridge0,
   Wridge0max,
   Zridgemid,
   Wridgemid,
   Wridgemidmax,
   Zridgeok,
   Wridgeok,
   Wridgeokmax,
   Zsetplane,
   Ztotcheck,
   Ztotmerge,
     ZEND};
 #endif
 
 /*---------------------------------
 
   ztype
     the type of a statistic sets its initial value.
 
   notes:
     The type should be the same as the macro for collecting the statistic
 */
 enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
 
 /*========== macros and constants =============*/
 
 /*----------------------------------
 
   MAYdebugx
     define as maydebug() to be called frequently for error trapping
 */
 #define MAYdebugx
 
 /*----------------------------------
 
   zzdef_, zdef_( type, name, doc, -1)
     define a statistic (assumes 'qhstat.next= 0;')
 
   zdef_( type, name, doc, count)
     define an averaged statistic
     printed as name/count
 */
 #define zzdef_(stype,name,string,cnt) qh->qhstat.id[qh->qhstat.next++]=name; \
    qh->qhstat.doc[name]= string; qh->qhstat.count[name]= cnt; qh->qhstat.type[name]= stype
 #if qh_KEEPstatistics
 #define zdef_(stype,name,string,cnt) qh->qhstat.id[qh->qhstat.next++]=name; \
    qh->qhstat.doc[name]= string; qh->qhstat.count[name]= cnt; qh->qhstat.type[name]= stype
 #else
 #define zdef_(type,name,doc,count)
 #endif
 
 /*----------------------------------
 
   zzinc_( name ), zinc_( name)
     increment an integer statistic
 */
 #define zzinc_(id) {MAYdebugx; qh->qhstat.stats[id].i++;}
 #if qh_KEEPstatistics
 #define zinc_(id) {MAYdebugx; qh->qhstat.stats[id].i++;}
 #else
 #define zinc_(id) {}
 #endif
 
 /*----------------------------------
 
   zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
     add value to an integer or real statistic
 */
 #define zzadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].i += (val);}
 #define wwadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].r += (val);}
 #if qh_KEEPstatistics
 #define zadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].i += (val);}
 #define wadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].r += (val);}
 #else
 #define zadd_(id, val) {}
 #define wadd_(id, val) {}
 #endif
 
 /*----------------------------------
 
   zzval_( name ), zval_( name ), wwval_( name )
     set or return value of a statistic
 */
 #define zzval_(id) ((qh->qhstat.stats[id]).i)
 #define wwval_(id) ((qh->qhstat.stats[id]).r)
 #if qh_KEEPstatistics
 #define zval_(id) ((qh->qhstat.stats[id]).i)
 #define wval_(id) ((qh->qhstat.stats[id]).r)
 #else
 #define zval_(id) qh->qhstat.tempi
 #define wval_(id) qh->qhstat.tempr
 #endif
 
 /*----------------------------------
 
   zmax_( id, val ), wmax_( id, value )
     maximize id with val
 */
 #define wwmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].r,(val));}
 #if qh_KEEPstatistics
 #define zmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].i,(val));}
 #define wmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].r,(val));}
 #else
 #define zmax_(id, val) {}
 #define wmax_(id, val) {}
 #endif
 
 /*----------------------------------
 
   zmin_( id, val ), wmin_( id, value )
     minimize id with val
 */
 #if qh_KEEPstatistics
 #define zmin_(id, val) {MAYdebugx; minimize_(qh->qhstat.stats[id].i,(val));}
 #define wmin_(id, val) {MAYdebugx; minimize_(qh->qhstat.stats[id].r,(val));}
 #else
 #define zmin_(id, val) {}
 #define wmin_(id, val) {}
 #endif
 
 /*================== stat_r.h types ==============*/
 
 
 /*----------------------------------
 
   intrealT
     union of integer and real, used for statistics
 */
 typedef union intrealT intrealT;    /* union of int and realT */
 union intrealT {
     int i;
     realT r;
 };
 
 /*----------------------------------
 
   qhstat
     Data structure for statistics, similar to qh and qhrbox
 
     Allocated as part of qhT (libqhull_r.h)
 */
 
 struct qhstatT {
   intrealT   stats[ZEND];     /* integer and real statistics */
   unsigned   char id[ZEND+10]; /* id's in print order */
   const char *doc[ZEND];       /* array of documentation strings */
   short int  count[ZEND];     /* -1 if none, else index of count to use */
   char       type[ZEND];      /* type, see ztypes above */
   char       printed[ZEND];   /* true, if statistic has been printed */
   intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
 
   int        next;            /* next index for zdef_ */
   int        precision;       /* index for precision problems */
   int        vridges;         /* index for Voronoi ridges */
   int        tempi;
   realT      tempr;
 };
 
 /*========== function prototypes ===========*/
 
 void    qh_allstatA(qhT *qh);
 void    qh_allstatB(qhT *qh);
 void    qh_allstatC(qhT *qh);
 void    qh_allstatD(qhT *qh);
 void    qh_allstatE(qhT *qh);
 void    qh_allstatE2(qhT *qh);
 void    qh_allstatF(qhT *qh);
 void    qh_allstatG(qhT *qh);
 void    qh_allstatH(qhT *qh);
 void    qh_allstatI(qhT *qh);
 void    qh_allstatistics(qhT *qh);
 void    qh_collectstatistics(qhT *qh);
 void    qh_initstatistics(qhT *qh);
 boolT   qh_newstats(qhT *qh, int idx, int *nextindex);
 boolT   qh_nostatistic(qhT *qh, int i);
 void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string);
 void    qh_printstatistics(qhT *qh, FILE *fp, const char *string);
 void    qh_printstatlevel(qhT *qh, FILE *fp, int id, int start);
 void    qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex);
 realT   qh_stddev(int num, realT tot, realT tot2, realT *ave);
 
 #endif   /* qhDEFstat */
diff --git a/src/qconvex/qconvex.c b/src/qconvex/qconvex.c
index a49642a..d6118ff 100644
--- a/src/qconvex/qconvex.c
+++ b/src/qconvex/qconvex.c
@@ -1,336 +1,336 @@
 /*
  ---------------------------------
 
    qconvex.c
       compute convex hulls using qhull
 
    see unix.c for full interface
 
-   Copyright (c) 1993-2014, The Geometry Center
+   Copyright (c) 1993-2015, The Geometry Center
 */
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include "libqhull.h"
 #include "mem.h"
 #include "qset.h"
 
 #if __MWERKS__ && __POWERPC__
 #include 
 #include 
 #include 
 #include 
 
 #elif __cplusplus
 extern "C" {
   int isatty(int);
 }
 
 #elif _MSC_VER
 #include 
 #define isatty _isatty
 int _isatty(int);
 
 #else
 int isatty(int);  /* returns 1 if stdin is a tty
                    if "Undefined symbol" this can be deleted along with call in main() */
 #endif
 
 /*---------------------------------
 
   qh_prompt
     long prompt for qconvex
 
   notes:
     restricted version of libqhull.c
 
   see:
     concise prompt below
 */
 
 /* duplicated in qconvex.htm */
 char hidden_options[]=" d v H Qbb Qf Qg Qm Qr Qu Qv Qx Qz TR E V Fp Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
 
 char qh_prompta[]= "\n\
 qconvex- compute the convex hull\n\
     http://www.qhull.org  %s\n\
 \n\
 input (stdin):\n\
     first lines: dimension and number of points (or vice-versa).\n\
     other lines: point coordinates, best if one point per line\n\
     comments:    start with a non-numeric character\n\
 \n\
 options:\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Qc   - keep coplanar points with nearest facet\n\
     Qi   - keep interior points with nearest facet\n\
 \n\
 Qhull control options:\n\
     Qbk:n   - scale coord k so that low bound is n\n\
       QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
     QbB  - scale input to unit cube centered at the origin\n\
     Qbk:0Bk:0 - remove k-th coordinate from input\n\
     QJn  - randomly joggle input in range [-n,n]\n\
     QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
 %s%s%s%s";  /* split up qh_prompt for Visual C++ */
 char qh_promptb[]= "\
     Qs   - search all points for the initial simplex\n\
     QGn  - good facet if visible from point n, -n for not visible\n\
     QVn  - good facet if it includes point n, -n if not\n\
 \n\
 ";
 char qh_promptc[]= "\
 Trace options:\n\
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
     Tc   - check frequently during execution\n\
     Ts   - print statistics\n\
     Tv   - verify result: structure, convexity, and point inclusion\n\
     Tz   - send all output to stdout\n\
     TFn  - report summary when n or more facets created\n\
     TI file - input data from file, no spaces or single quotes\n\
     TO file - output results to file, may be enclosed in single quotes\n\
     TPn  - turn on tracing when point n added to hull\n\
      TMn - turn on tracing at merge n\n\
      TWn - trace merge facets when width > n\n\
     TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
      TCn - stop qhull after building cone for point n (see TVn)\n\
 \n\
 Precision options:\n\
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
     Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
     Un   - max distance below plane for a new, coplanar point\n\
     Wn   - min facet width for outside point (before roundoff)\n\
 \n\
 Output formats (may be combined; if none, produces a summary to stdout):\n\
     f    - facet dump\n\
     G    - Geomview output (see below)\n\
     i    - vertices incident to each facet\n\
     m    - Mathematica output (2-d and 3-d)\n\
     n    - normals with offsets\n\
     o    - OFF file format (dim, points and facets; Voronoi regions)\n\
     p    - point coordinates \n\
     s    - summary (stderr)\n\
 \n\
 ";
 char qh_promptd[]= "\
 More formats:\n\
     Fa   - area for each facet\n\
     FA   - compute total area and volume for option 's'\n\
     Fc   - count plus coplanar points for each facet\n\
            use 'Qc' (default) for coplanar and 'Qi' for interior\n\
     FC   - centrum for each facet\n\
     Fd   - use cdd format for input (homogeneous with offset first)\n\
     FD   - use cdd format for numeric output (offset first)\n\
     FF   - facet dump without ridges\n\
     Fi   - inner plane for each facet\n\
     FI   - ID for each facet\n\
     Fm   - merge count for each facet (511 max)\n\
     Fn   - count plus neighboring facets for each facet\n\
     FN   - count plus neighboring facets for each point\n\
     Fo   - outer plane (or max_outside) for each facet\n\
     FO   - options and precision constants\n\
     FP   - nearest vertex for each coplanar point\n\
     FQ   - command used for qconvex\n\
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                       for output: #vertices, #facets,\n\
                                   #coplanar points, #non-simplicial facets\n\
                     #real (2), max outer plane, min vertex\n\
     FS   - sizes:   #int (0) \n\
                     #real (2) tot area, tot volume\n\
     Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
     Fv   - count plus vertices for each facet\n\
     FV   - average of vertices (a feasible point for 'H')\n\
     Fx   - extreme points (in order for 2-d)\n\
 \n\
 ";
 char qh_prompte[]= "\
 Geomview output (2-d, 3-d, and 4-d)\n\
     Ga   - all points as dots\n\
      Gp  -  coplanar points and vertices as radii\n\
      Gv  -  vertices as spheres\n\
     Gi   - inner planes only\n\
      Gn  -  no planes\n\
      Go  -  outer planes only\n\
     Gc   - centrums\n\
     Gh   - hyperplane intersections\n\
     Gr   - ridges\n\
     GDn  - drop dimension n in 3-d and 4-d output\n\
 \n\
 Print options:\n\
     PAn  - keep n largest facets by area\n\
     Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
     PDk:n - drop facet if normal[k] >= n\n\
     Pg   - print good facets (needs 'QGn' or 'QVn')\n\
     PFn  - keep facets whose area is at least n\n\
     PG   - print neighbors of good facets\n\
     PMn  - keep n facets with most merges\n\
     Po   - force output.  If error, output neighborhood of facet\n\
     Pp   - do not report precision problems\n\
 \n\
     .    - list of all options\n\
     -    - one line descriptions of all options\n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt2
     synopsis for qhull
 */
 char qh_prompt2[]= "\n\
 qconvex- compute the convex hull.  Qhull %s\n\
     input (stdin): dimension, number of points, point coordinates\n\
     comments start with a non-numeric character\n\
 \n\
 options (qconvex.htm):\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Tv   - verify result: structure, convexity, and point inclusion\n\
     .    - concise list of all options\n\
     -    - one-line description of all options\n\
 \n\
 output options (subset):\n\
     s    - summary of results (default)\n\
     i    - vertices incident to each facet\n\
     n    - normals with offsets\n\
     p    - vertex coordinates (includes coplanar points if 'Qc')\n\
     Fx   - extreme points (convex hull vertices)\n\
     FA   - report total area and volume\n\
     FS   - compute total area and volume\n\
     o    - OFF format (dim, n, points, facets)\n\
     G    - Geomview output (2-d, 3-d, and 4-d)\n\
     m    - Mathematica output (2-d and 3-d)\n\
     QVn  - print facets that include point n, -n if not\n\
     TO file- output results to file, may be enclosed in single quotes\n\
 \n\
 examples:\n\
     rbox c D2 | qconvex s n                    rbox c D2 | qconvex i\n\
     rbox c D2 | qconvex o                      rbox 1000 s | qconvex s Tv FA\n\
     rbox c d D2 | qconvex s Qc Fx              rbox y 1000 W0 | qconvex s n\n\
     rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp\n\
     rbox c D7 | qconvex FA TF1000\n\
 \n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt3
     concise prompt for qhull
 */
 char qh_prompt3[]= "\n\
 Qhull %s.\n\
 Except for 'F.' and 'PG', upper-case options take an argument.\n\
 \n\
  incidences     mathematica    normals        OFF_format     points\n\
  summary        facet_dump\n\
 \n\
  Farea          FArea_total    Fcoplanars     FCentrums      Fd_cdd_in\n\
  FD_cdd_out     FFacet_xridge  Finner         FIDs           Fmerges\n\
  Fneighbors     FNeigh_vertex  Fouter         FOptions       FPoint_near\n\
  FQhull         Fsummary       FSize          Fvertices      FVertex_ave\n\
  Fxtremes       FMaple\n\
 \n\
  Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
  Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
 \n\
  PArea_keep     Pdrop d0:0D0   PFacet_area_keep Pgood        PGood_neighbors\n\
  PMerge_keep    Poutput_forced Pprecision_not\n\
 \n\
  QbBound 0:0.5  QbB_scale_box  Qcoplanar      QGood_point    Qinterior\n\
  QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
  QVertex_good\n\
 \n\
  T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
  TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
  TWide_trace    TVertex_stop   TCone_stop\n\
 \n\
  Angle_max      Centrum_size   Random_dist    Ucoplanar_max  Wide_outside\n\
 ";
 
 /*---------------------------------
 
   main( argc, argv )
     processes the command line, calls qhull() to do the work, and exits
 
   design:
     initializes data structures
     reads points
     finishes initialization
     computes convex hull and other structures
     checks the result
     writes the output
     frees memory
 */
 int main(int argc, char *argv[]) {
   int curlong, totlong; /* used !qh_NOmem */
   int exitcode, numpoints, dim;
   coordT *points;
   boolT ismalloc;
 
 #if __MWERKS__ && __POWERPC__
   char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
   SIOUXSettings.showstatusline= false;
   SIOUXSettings.tabspaces= 1;
   SIOUXSettings.rows= 40;
   if (setvbuf(stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
   || setvbuf(stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
   || (stdout != stderr && setvbuf(stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
     fprintf(stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
   argc= ccommand(&argv);
 #endif
 
   if ((argc == 1) && isatty( 0 /*stdin*/)) {
     fprintf(stdout, qh_prompt2, qh_version);
     exit(qh_ERRnone);
   }
   if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompta, qh_version, qh_DEFAULTbox,
                 qh_promptb, qh_promptc, qh_promptd, qh_prompte);
     exit(qh_ERRnone);
   }
   if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompt3, qh_version);
     exit(qh_ERRnone);
   }
   qh_init_A(stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
   exitcode= setjmp(qh errexit); /* simple statement for CRAY J916 */
   if (!exitcode) {
     qh_checkflags(qh qhull_command, hidden_options);
     qh_initflags(qh qhull_command);
     points= qh_readpoints(&numpoints, &dim, &ismalloc);
     if (dim >= 5) {
       qh_option("Qxact_merge", NULL, NULL);
       qh MERGEexact= True; /* 'Qx' always */
     }
     qh_init_B(points, numpoints, dim, ismalloc);
     qh_qhull();
     qh_check_output();
     qh_produce_output();
     if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
       qh_check_points();
     exitcode= qh_ERRnone;
   }
   qh NOerrexit= True;  /* no more setjmp */
 #ifdef qh_NOmem
   qh_freeqhull( True);
 #else
   qh_freeqhull( False);
   qh_memfreeshort(&curlong, &totlong);
   if (curlong || totlong)
     fprintf(stderr, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
        totlong, curlong);
 #endif
   return exitcode;
 } /* main */
 
diff --git a/src/qdelaunay/qdelaun.c b/src/qdelaunay/qdelaun.c
index 3c111e0..a67c0ee 100644
--- a/src/qdelaunay/qdelaun.c
+++ b/src/qdelaunay/qdelaun.c
@@ -1,325 +1,325 @@
 /*
  ---------------------------------
 
    qdelaun.c
      compute Delaunay triangulations and furthest-point Delaunay
      triangulations using qhull
 
    see unix.c for full interface
 
-   Copyright (c) 1993-2014, The Geometry Center
+   Copyright (c) 1993-2015, The Geometry Center
 */
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include "libqhull.h"
 #include "mem.h"
 #include "qset.h"
 
 #if __MWERKS__ && __POWERPC__
 #include 
 #include 
 #include 
 #include 
 
 #elif __cplusplus
 extern "C" {
   int isatty(int);
 }
 
 #elif _MSC_VER
 #include 
 #define isatty _isatty
 int _isatty(int);
 
 #else
 int isatty(int);  /* returns 1 if stdin is a tty
                    if "Undefined symbol" this can be deleted along with call in main() */
 #endif
 
 /*---------------------------------
 
   qh_prompt
     long prompt for qhull
 
   notes:
     restricted version of libqhull.c
 
   see:
     concise prompt below
 */
 
 /* duplicated in qdelau_f.htm and qdelaun.htm */
 char hidden_options[]=" d n v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V FC Fi Fo Ft Fp FV Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
 
 char qh_prompta[]= "\n\
 qdelaunay- compute the Delaunay triangulation\n\
     http://www.qhull.org  %s\n\
 \n\
 input (stdin):\n\
     first lines: dimension and number of points (or vice-versa).\n\
     other lines: point coordinates, best if one point per line\n\
     comments:    start with a non-numeric character\n\
 \n\
 options:\n\
     Qu   - compute furthest-site Delaunay triangulation\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
 \n\
 Qhull control options:\n\
     QJn  - randomly joggle input in range [-n,n]\n\
 %s%s%s%s";  /* split up qh_prompt for Visual C++ */
 char qh_promptb[]= "\
     Qs   - search all points for the initial simplex\n\
     Qz   - add point-at-infinity to Delaunay triangulation\n\
     QGn  - print Delaunay region if visible from point n, -n if not\n\
     QVn  - print Delaunay regions that include point n, -n if not\n\
 \n\
 ";
 char qh_promptc[]= "\
 Trace options:\n\
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
     Tc   - check frequently during execution\n\
     Ts   - print statistics\n\
     Tv   - verify result: structure, convexity, and in-circle test\n\
     Tz   - send all output to stdout\n\
     TFn  - report summary when n or more facets created\n\
     TI file - input data from file, no spaces or single quotes\n\
     TO file - output results to file, may be enclosed in single quotes\n\
     TPn  - turn on tracing when point n added to hull\n\
      TMn - turn on tracing at merge n\n\
      TWn - trace merge facets when width > n\n\
     TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
      TCn - stop qhull after building cone for point n (see TVn)\n\
 \n\
 Precision options:\n\
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
     Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
     Wn   - min facet width for outside point (before roundoff)\n\
 \n\
 Output formats (may be combined; if none, produces a summary to stdout):\n\
     f    - facet dump\n\
     G    - Geomview output (see below)\n\
     i    - vertices incident to each Delaunay region\n\
     m    - Mathematica output (2-d only, lifted to a paraboloid)\n\
     o    - OFF format (dim, points, and facets as a paraboloid)\n\
     p    - point coordinates (lifted to a paraboloid)\n\
     s    - summary (stderr)\n\
 \n\
 ";
 char qh_promptd[]= "\
 More formats:\n\
     Fa   - area for each Delaunay region\n\
     FA   - compute total area for option 's'\n\
     Fc   - count plus coincident points for each Delaunay region\n\
     Fd   - use cdd format for input (homogeneous with offset first)\n\
     FD   - use cdd format for numeric output (offset first)\n\
     FF   - facet dump without ridges\n\
     FI   - ID of each Delaunay region\n\
     Fm   - merge count for each Delaunay region (511 max)\n\
     FM   - Maple output (2-d only, lifted to a paraboloid)\n\
     Fn   - count plus neighboring region for each Delaunay region\n\
     FN   - count plus neighboring region for each point\n\
     FO   - options and precision constants\n\
     FP   - nearest point and distance for each coincident point\n\
     FQ   - command used for qdelaunay\n\
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                     for output: #vertices, #Delaunay regions,\n\
                                 #coincident points, #non-simplicial regions\n\
                     #real (2), max outer plane, min vertex\n\
     FS   - sizes:   #int (0)\n\
                     #real (2), tot area, 0\n\
     Fv   - count plus vertices for each Delaunay region\n\
     Fx   - extreme points of Delaunay triangulation (on convex hull)\n\
 \n\
 ";
 char qh_prompte[]= "\
 Geomview options (2-d and 3-d)\n\
     Ga   - all points as dots\n\
      Gp  -  coplanar points and vertices as radii\n\
      Gv  -  vertices as spheres\n\
     Gi   - inner planes only\n\
      Gn  -  no planes\n\
      Go  -  outer planes only\n\
     Gc     - centrums\n\
     Gh   - hyperplane intersections\n\
     Gr   - ridges\n\
     GDn  - drop dimension n in 3-d and 4-d output\n\
     Gt   - transparent outer ridges to view 3-d Delaunay\n\
 \n\
 Print options:\n\
     PAn  - keep n largest Delaunay regions by area\n\
     Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
     PDk:n - drop facet if normal[k] >= n\n\
     Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')\n\
     PFn  - keep Delaunay regions whose area is at least n\n\
     PG   - print neighbors of good regions (needs 'QGn' or 'QVn')\n\
     PMn  - keep n Delaunay regions with most merges\n\
     Po   - force output.  If error, output neighborhood of facet\n\
     Pp   - do not report precision problems\n\
 \n\
     .    - list of all options\n\
     -    - one line descriptions of all options\n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt2
     synopsis for qhull
 */
 char qh_prompt2[]= "\n\
 qdelaunay- compute the Delaunay triangulation.  Qhull %s\n\
     input (stdin): dimension, number of points, point coordinates\n\
     comments start with a non-numeric character\n\
 \n\
 options (qdelaun.htm):\n\
     Qu   - furthest-site Delaunay triangulation\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Tv   - verify result: structure, convexity, and in-circle test\n\
     .    - concise list of all options\n\
     -    - one-line description of all options\n\
 \n\
 output options (subset):\n\
     s    - summary of results (default)\n\
     i    - vertices incident to each Delaunay region\n\
     Fx   - extreme points (vertices of the convex hull)\n\
     o    - OFF format (shows the points lifted to a paraboloid)\n\
     G    - Geomview output (2-d and 3-d points lifted to a paraboloid)\n\
     m    - Mathematica output (2-d inputs lifted to a paraboloid)\n\
     QVn  - print Delaunay regions that include point n, -n if not\n\
     TO file- output results to file, may be enclosed in single quotes\n\
 \n\
 examples:\n\
     rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i\n\
     rbox c P0 D2 | qdelaunay Fv           rbox c P0 D2 | qdelaunay s Qu Fv\n\
     rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay Qt\n\
     rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt\n\
 \n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt3
     concise prompt for qhull
 */
 char qh_prompt3[]= "\n\
 Qhull %s.\n\
 Except for 'F.' and 'PG', upper-case options take an argument.\n\
 \n\
  incidences     mathematica    OFF_format     points_lifted  summary\n\
  facet_dump\n\
 \n\
  Farea          FArea_total    Fcoincident    Fd_cdd_in      FD_cdd_out\n\
  FF_dump_xridge FIDs           Fmerges        Fneighbors     FNeigh_vertex\n\
  FOptions       FPoint_near    FQdelaun       Fsummary       FSize\n\
  Fvertices      Fxtremes       FMaple\n\
 \n\
  Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
  Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
  Gtransparent\n\
 \n\
  PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
  PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
 \n\
  QGood_point    QJoggle        Qsearch_1st    Qtriangulate   QupperDelaunay\n\
  QVertex_good   Qzinfinite\n\
 \n\
  T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
  TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
  TWide_trace    TVertex_stop   TCone_stop\n\
 \n\
  Angle_max      Centrum_size   Random_dist    Wide_outside\n\
 ";
 
 /*---------------------------------
 
   main( argc, argv )
     processes the command line, calls qhull() to do the work, and exits
 
   design:
     initializes data structures
     reads points
     finishes initialization
     computes convex hull and other structures
     checks the result
     writes the output
     frees memory
 */
 int main(int argc, char *argv[]) {
   int curlong, totlong; /* used !qh_NOmem */
   int exitcode, numpoints, dim;
   coordT *points;
   boolT ismalloc;
 
 #if __MWERKS__ && __POWERPC__
   char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
   SIOUXSettings.showstatusline= false;
   SIOUXSettings.tabspaces= 1;
   SIOUXSettings.rows= 40;
   if (setvbuf(stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
   || setvbuf(stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
   || (stdout != stderr && setvbuf(stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
     fprintf(stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
   argc= ccommand(&argv);
 #endif
 
   if ((argc == 1) && isatty( 0 /*stdin*/)) {
     fprintf(stdout, qh_prompt2, qh_version);
     exit(qh_ERRnone);
   }
   if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompta, qh_version,
                 qh_promptb, qh_promptc, qh_promptd, qh_prompte);
     exit(qh_ERRnone);
   }
   if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompt3, qh_version);
     exit(qh_ERRnone);
   }
   qh_init_A(stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
   exitcode= setjmp(qh errexit); /* simple statement for CRAY J916 */
   if (!exitcode) {
     qh_option("delaunay  Qbbound-last", NULL, NULL);
     qh DELAUNAY= True;     /* 'd'   */
     qh SCALElast= True;    /* 'Qbb' */
     qh KEEPcoplanar= True; /* 'Qc', to keep coplanars in 'p' */
     qh_checkflags(qh qhull_command, hidden_options);
     qh_initflags(qh qhull_command);
     points= qh_readpoints(&numpoints, &dim, &ismalloc);
     if (dim >= 5) {
       qh_option("Qxact_merge", NULL, NULL);
       qh MERGEexact= True; /* 'Qx' always */
     }
     qh_init_B(points, numpoints, dim, ismalloc);
     qh_qhull();
     qh_check_output();
     qh_produce_output();
     if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
       qh_check_points();
     exitcode= qh_ERRnone;
   }
   qh NOerrexit= True;  /* no more setjmp */
 #ifdef qh_NOmem
   qh_freeqhull( True);
 #else
   qh_freeqhull( False);
   qh_memfreeshort(&curlong, &totlong);
   if (curlong || totlong)
     fprintf(stderr, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
        totlong, curlong);
 #endif
   return exitcode;
 } /* main */
 
diff --git a/src/qhalf/qhalf.c b/src/qhalf/qhalf.c
index 115854c..2bd8286 100644
--- a/src/qhalf/qhalf.c
+++ b/src/qhalf/qhalf.c
@@ -1,326 +1,326 @@
 /*
  ---------------------------------
 
    qhalf.c
      compute the intersection of halfspaces about a point
 
    see unix.c for full interface
 
-   Copyright (c) 1993-2014, The Geometry Center
+   Copyright (c) 1993-2015, The Geometry Center
 */
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include "libqhull.h"
 #include "mem.h"
 #include "qset.h"
 
 #if __MWERKS__ && __POWERPC__
 #include 
 #include 
 #include 
 #include 
 
 #elif __cplusplus
 extern "C" {
   int isatty(int);
 }
 
 #elif _MSC_VER
 #include 
 #define isatty _isatty
 int _isatty(int);
 
 #else
 int isatty(int);  /* returns 1 if stdin is a tty
                    if "Undefined symbol" this can be deleted along with call in main() */
 #endif
 
 /*---------------------------------
 
   qh_prompt
     long prompt for qhull
 
   notes:
     restricted version of libqhull.c
 
   see:
     concise prompt below
 */
 
 /* duplicated in qhalf.htm */
 char hidden_options[]=" d n v Qbb QbB Qf Qg Qm Qr QR Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
 
 char qh_prompta[]= "\n\
 qhalf- compute the intersection of halfspaces about a point\n\
     http://www.qhull.org  %s\n\
 \n\
 input (stdin):\n\
     optional interior point: dimension, 1, coordinates\n\
     first lines: dimension+1 and number of halfspaces\n\
     other lines: halfspace coefficients followed by offset\n\
     comments:    start with a non-numeric character\n\
 \n\
 options:\n\
     Hn,n - specify coordinates of interior point\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Qc   - keep coplanar halfspaces\n\
     Qi   - keep other redundant halfspaces\n\
 \n\
 Qhull control options:\n\
     QJn  - randomly joggle input in range [-n,n]\n\
 %s%s%s%s";  /* split up qh_prompt for Visual C++ */
 char qh_promptb[]= "\
     Qbk:0Bk:0 - remove k-th coordinate from input\n\
     Qs   - search all halfspaces for the initial simplex\n\
     QGn  - print intersection if visible to halfspace n, -n for not\n\
     QVn  - print intersections for halfspace n, -n if not\n\
 \n\
 ";
 char qh_promptc[]= "\
 Trace options:\n\
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
     Tc   - check frequently during execution\n\
     Ts   - print statistics\n\
     Tv   - verify result: structure, convexity, and redundancy\n\
     Tz   - send all output to stdout\n\
     TFn  - report summary when n or more facets created\n\
     TI file - input data from file, no spaces or single quotes\n\
     TO file - output results to file, may be enclosed in single quotes\n\
     TPn  - turn on tracing when halfspace n added to intersection\n\
     TMn  - turn on tracing at merge n\n\
     TWn  - trace merge facets when width > n\n\
     TVn  - stop qhull after adding halfspace n, -n for before (see TCn)\n\
     TCn  - stop qhull after building cone for halfspace n (see TVn)\n\
 \n\
 Precision options:\n\
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
     Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
     Un   - max distance below plane for a new, coplanar halfspace\n\
     Wn   - min facet width for outside halfspace (before roundoff)\n\
 \n\
 Output formats (may be combined; if none, produces a summary to stdout):\n\
     f    - facet dump\n\
     G    - Geomview output (dual convex hull)\n\
     i    - non-redundant halfspaces incident to each intersection\n\
     m    - Mathematica output (dual convex hull)\n\
     o    - OFF format (dual convex hull: dimension, points, and facets)\n\
     p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')\n\
     s    - summary (stderr)\n\
 \n\
 ";
 char qh_promptd[]= "\
 More formats:\n\
     Fc   - count plus redundant halfspaces for each intersection\n\
          -   Qc (default) for coplanar and Qi for other redundant\n\
     Fd   - use cdd format for input (homogeneous with offset first)\n\
     FF   - facet dump without ridges\n\
     FI   - ID of each intersection\n\
     Fm   - merge count for each intersection (511 max)\n\
     FM   - Maple output (dual convex hull)\n\
     Fn   - count plus neighboring intersections for each intersection\n\
     FN   - count plus intersections for each non-redundant halfspace\n\
     FO   - options and precision constants\n\
     Fp   - dim, count, and intersection coordinates\n\
     FP   - nearest halfspace and distance for each redundant halfspace\n\
     FQ   - command used for qhalf\n\
     Fs   - summary: #int (8), dim, #halfspaces, #non-redundant, #intersections\n\
                       for output: #non-redundant, #intersections, #coplanar\n\
                                   halfspaces, #non-simplicial intersections\n\
                     #real (2), max outer plane, min vertex\n\
     Fv   - count plus non-redundant halfspaces for each intersection\n\
     Fx   - non-redundant halfspaces\n\
 \n\
 ";
 char qh_prompte[]= "\
 Geomview output (2-d, 3-d and 4-d; dual convex hull)\n\
     Ga   - all points (i.e., transformed halfspaces) as dots\n\
      Gp  -  coplanar points and vertices as radii\n\
      Gv  -  vertices (i.e., non-redundant halfspaces) as spheres\n\
     Gi   - inner planes (i.e., halfspace intersections) only\n\
      Gn  -  no planes\n\
      Go  -  outer planes only\n\
     Gc   - centrums\n\
     Gh   - hyperplane intersections\n\
     Gr   - ridges\n\
     GDn  - drop dimension n in 3-d and 4-d output\n\
 \n\
 Print options:\n\
     PAn  - keep n largest facets (i.e., intersections) by area\n\
     Pdk:n- drop facet if normal[k] <= n (default 0.0)\n\
     PDk:n- drop facet if normal[k] >= n\n\
     Pg   - print good facets (needs 'QGn' or 'QVn')\n\
     PFn  - keep facets whose area is at least n\n\
     PG   - print neighbors of good facets\n\
     PMn  - keep n facets with most merges\n\
     Po   - force output.  If error, output neighborhood of facet\n\
     Pp   - do not report precision problems\n\
 \n\
     .    - list of all options\n\
     -    - one line descriptions of all options\n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt2
     synopsis for qhull
 */
 char qh_prompt2[]= "\n\
 qhalf- halfspace intersection about a point.  Qhull %s\n\
     input (stdin): [dim, 1, interior point], dim+1, n, coefficients+offset\n\
     comments start with a non-numeric character\n\
 \n\
 options (qhalf.htm):\n\
     Hn,n - specify coordinates of interior point\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Tv   - verify result: structure, convexity, and redundancy\n\
     .    - concise list of all options\n\
     -    - one-line description of all options\n\
 \n\
 output options (subset):\n\
     s    - summary of results (default)\n\
     Fp   - intersection coordinates\n\
     Fv   - non-redundant halfspaces incident to each intersection\n\
     Fx   - non-redundant halfspaces\n\
     o    - OFF file format (dual convex hull)\n\
     G    - Geomview output (dual convex hull)\n\
     m    - Mathematica output (dual convex hull)\n\
     QVn  - print intersections for halfspace n, -n if not\n\
     TO file - output results to file, may be enclosed in single quotes\n\
 \n\
 examples:\n\
     rbox d | qconvex FQ n | qhalf s H0,0,0 Fp\n\
     rbox c | qconvex FQ FV n | qhalf s i\n\
     rbox c | qconvex FQ FV n | qhalf s o\n\
 \n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt3
     concise prompt for qhull
 */
 char qh_prompt3[]= "\n\
 Qhull %s.\n\
 Except for 'F.' and 'PG', upper_case options take an argument.\n\
 \n\
  incidences     Geomview       mathematica    OFF_format     point_dual\n\
  summary        facet_dump\n\
 \n\
  Fc_redundant   Fd_cdd_in      FF_dump_xridge FIDs           Fmerges\n\
  Fneighbors     FN_intersect   FOptions       Fp_coordinates FP_nearest\n\
  FQhalf         Fsummary       Fv_halfspace   FMaple         Fx_non_redundant\n\
 \n\
  Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
  Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
 \n\
  PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
  PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
 \n\
  Qbk:0Bk:0_drop Qcoplanar      QG_half_good   Qi_redundant   QJoggle\n\
  Qsearch_1st    Qtriangulate   QVertex_good\n\
 \n\
  T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
  TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
  TWide_trace    TVertex_stop   TCone_stop\n\
 \n\
  Angle_max      Centrum_size   Random_dist    Ucoplanar_max  Wide_outside\n\
 ";
 
 /*---------------------------------
 
   main( argc, argv )
     processes the command line, calls qhull() to do the work, and exits
 
   design:
     initializes data structures
     reads points
     finishes initialization
     computes convex hull and other structures
     checks the result
     writes the output
     frees memory
 */
 int main(int argc, char *argv[]) {
   int curlong, totlong; /* used !qh_NOmem */
   int exitcode, numpoints, dim;
   coordT *points;
   boolT ismalloc;
 
 #if __MWERKS__ && __POWERPC__
   char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
   SIOUXSettings.showstatusline= false;
   SIOUXSettings.tabspaces= 1;
   SIOUXSettings.rows= 40;
   if (setvbuf(stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
   || setvbuf(stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
   || (stdout != stderr && setvbuf(stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
     fprintf(stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
   argc= ccommand(&argv);
 #endif
 
   if ((argc == 1) && isatty( 0 /*stdin*/)) {
     fprintf(stdout, qh_prompt2, qh_version);
     exit(qh_ERRnone);
   }
   if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompta, qh_version,
         qh_promptb, qh_promptc, qh_promptd, qh_prompte);
     exit(qh_ERRnone);
   }
   if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompt3, qh_version);
     exit(qh_ERRnone);
   }
   qh_init_A(stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
   exitcode= setjmp(qh errexit); /* simple statement for CRAY J916 */
   if (!exitcode) {
     qh_option("Halfspace", NULL, NULL);
     qh HALFspace= True;    /* 'H'   */
     qh_checkflags(qh qhull_command, hidden_options);
     qh_initflags(qh qhull_command);
     if (qh SCALEinput) {
       fprintf(qh ferr, "\
 qhull error: options 'Qbk:n' and 'QBk:n' are not used with qhalf.\n\
              Use 'Qbk:0Bk:0 to drop dimension k.\n");
       qh_errexit(qh_ERRinput, NULL, NULL);
     }
     points= qh_readpoints(&numpoints, &dim, &ismalloc);
     if (dim >= 5) {
       qh_option("Qxact_merge", NULL, NULL);
       qh MERGEexact= True; /* 'Qx' always */
     }
     qh_init_B(points, numpoints, dim, ismalloc);
     qh_qhull();
     qh_check_output();
     qh_produce_output();
     if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
       qh_check_points();
     exitcode= qh_ERRnone;
   }
   qh NOerrexit= True;  /* no more setjmp */
 #ifdef qh_NOmem
   qh_freeqhull( True);
 #else
   qh_freeqhull( False);
   qh_memfreeshort(&curlong, &totlong);
   if (curlong || totlong)
     fprintf(stderr, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
        totlong, curlong);
 #endif
   return exitcode;
 } /* main */
 
diff --git a/src/qhull/unix.c b/src/qhull/unix.c
index 81885c0..7acef85 100644
--- a/src/qhull/unix.c
+++ b/src/qhull/unix.c
@@ -1,382 +1,382 @@
 /*
  ---------------------------------
 
    unix.c
      command line interface to qhull
          includes SIOUX interface for Macintoshes
 
    see qh-qhull.htm
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/qhull/unix.c#5 $$Change: 1464 $
-   $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/qhull/unix.c#7 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "mem.h"
 #include "qset.h"
 #include "libqhull.h"
 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 #if __MWERKS__ && __POWERPC__
 #include 
 #include 
 #include 
 #include 
 
 #elif __cplusplus
 extern "C" {
   int isatty(int);
 }
 
 #elif _MSC_VER
 #include 
 #define isatty _isatty
 int _isatty(int);
 
 #else
 int isatty(int);  /* returns 1 if stdin is a tty
                    if "Undefined symbol" this can be deleted along with call in main() */
 #endif
 
 /*---------------------------------
 
   qh_prompt
     long prompt for qhull
 
   see:
     concise prompt below
 */
 char qh_prompta[]= "\n\
 qhull- compute convex hulls and related structures.\n\
     http://www.qhull.org  %s\n\
 \n\
 input (stdin):\n\
     first lines: dimension and number of points (or vice-versa).\n\
     other lines: point coordinates, best if one point per line\n\
     comments:    start with a non-numeric character\n\
     halfspaces:  use dim plus one and put offset after coefficients.\n\
                  May be preceeded by a single interior point ('H').\n\
 \n\
 options:\n\
     d    - Delaunay triangulation by lifting points to a paraboloid\n\
     d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
     v    - Voronoi diagram (dual of the Delaunay triangulation)\n\
     v Qu - furthest-site Voronoi diagram\n\
     Hn,n,... - halfspace intersection about point [n,n,0,...]\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Qc   - keep coplanar points with nearest facet\n\
     Qi   - keep interior points with nearest facet\n\
 \n\
 Qhull control options:\n\
     Qbk:n   - scale coord k so that low bound is n\n\
       QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
     QbB  - scale input to unit cube centered at the origin\n\
     Qbb  - scale last coordinate to [0,m] for Delaunay triangulations\n\
     Qbk:0Bk:0 - remove k-th coordinate from input\n\
     QJn  - randomly joggle input in range [-n,n]\n\
     QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
 %s%s%s%s";  /* split up qh_prompt for Visual C++ */
 char qh_promptb[]= "\
     Qf   - partition point to furthest outside facet\n\
     Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')\n\
     Qm   - only process points that would increase max_outside\n\
     Qr   - process random outside points instead of furthest ones\n\
     Qs   - search all points for the initial simplex\n\
     Qu   - for 'd' or 'v', compute upper hull without point at-infinity\n\
               returns furthest-site Delaunay triangulation\n\
     Qv   - test vertex neighbors for convexity\n\
     Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)\n\
     Qz   - add point-at-infinity to Delaunay triangulation\n\
     QGn  - good facet if visible from point n, -n for not visible\n\
     QVn  - good facet if it includes point n, -n if not\n\
     Q0   - turn off default premerge with 'C-0'/'Qx'\n\
     Q1     - sort merges by type instead of angle\n\
     Q2   - merge all non-convex at once instead of independent sets\n\
     Q3   - do not merge redundant vertices\n\
     Q4   - avoid old->new merges\n\
     Q5   - do not correct outer planes at end of qhull\n\
     Q6   - do not pre-merge concave or coplanar facets\n\
     Q7   - depth-first processing instead of breadth-first\n\
     Q8   - do not process near-inside points\n\
     Q9   - process furthest of furthest points\n\
     Q10  - no special processing for narrow distributions\n\
     Q11  - copy normals and recompute centrums for tricoplanar facets\n\
 \n\
 ";
 char qh_promptc[]= "\
 Topts- Trace options:\n\
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
     Ta   - annotate output with message codes\n\
     Tc   - check frequently during execution\n\
     Ts   - print statistics\n\
     Tv   - verify result: structure, convexity, and point inclusion\n\
     Tz   - send all output to stdout\n\
     TFn  - report summary when n or more facets created\n\
     TI file - input data from file, no spaces or single quotes\n\
     TO file - output results to file, may be enclosed in single quotes\n\
     TPn  - turn on tracing when point n added to hull\n\
      TMn - turn on tracing at merge n\n\
      TWn - trace merge facets when width > n\n\
     TRn  - rerun qhull n times.  Use with 'QJn'\n\
     TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
      TCn - stop qhull after building cone for point n (see TVn)\n\
 \n\
 Precision options:\n\
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
     En   - max roundoff error for distance computation\n\
     Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
     Vn   - min distance above plane for a visible facet (default 3C-n or En)\n\
     Un   - max distance below plane for a new, coplanar point (default Vn)\n\
     Wn   - min facet width for outside point (before roundoff, default 2Vn)\n\
 \n\
 Output formats (may be combined; if none, produces a summary to stdout):\n\
     f    - facet dump\n\
     G    - Geomview output (see below)\n\
     i    - vertices incident to each facet\n\
     m    - Mathematica output (2-d and 3-d)\n\
     o    - OFF format (dim, points and facets; Voronoi regions)\n\
     n    - normals with offsets\n\
     p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')\n\
     s    - summary (stderr)\n\
 \n\
 ";
 char qh_promptd[]= "\
 More formats:\n\
     Fa   - area for each facet\n\
     FA   - compute total area and volume for option 's'\n\
     Fc   - count plus coplanar points for each facet\n\
            use 'Qc' (default) for coplanar and 'Qi' for interior\n\
     FC   - centrum or Voronoi center for each facet\n\
     Fd   - use cdd format for input (homogeneous with offset first)\n\
     FD   - use cdd format for numeric output (offset first)\n\
     FF   - facet dump without ridges\n\
     Fi   - inner plane for each facet\n\
            for 'v', separating hyperplanes for bounded Voronoi regions\n\
     FI   - ID of each facet\n\
     Fm   - merge count for each facet (511 max)\n\
     FM   - Maple output (2-d and 3-d)\n\
     Fn   - count plus neighboring facets for each facet\n\
     FN   - count plus neighboring facets for each point\n\
     Fo   - outer plane (or max_outside) for each facet\n\
            for 'v', separating hyperplanes for unbounded Voronoi regions\n\
     FO   - options and precision constants\n\
     Fp   - dim, count, and intersection coordinates (halfspace only)\n\
     FP   - nearest vertex and distance for each coplanar point\n\
     FQ   - command used for qhull\n\
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                       output: #vertices, #facets, #coplanars, #nonsimplicial\n\
                     #real (2), max outer plane, min vertex\n\
     FS   - sizes:   #int (0)\n\
                     #real (2) tot area, tot volume\n\
     Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
     Fv   - count plus vertices for each facet\n\
            for 'v', Voronoi diagram as Voronoi vertices for pairs of sites\n\
     FV   - average of vertices (a feasible point for 'H')\n\
     Fx   - extreme points (in order for 2-d)\n\
 \n\
 ";
 char qh_prompte[]= "\
 Geomview options (2-d, 3-d, and 4-d; 2-d Voronoi)\n\
     Ga   - all points as dots\n\
      Gp  -  coplanar points and vertices as radii\n\
      Gv  -  vertices as spheres\n\
     Gi   - inner planes only\n\
      Gn  -  no planes\n\
      Go  -  outer planes only\n\
     Gc   - centrums\n\
     Gh   - hyperplane intersections\n\
     Gr   - ridges\n\
     GDn  - drop dimension n in 3-d and 4-d output\n\
     Gt   - for 3-d 'd', transparent outer ridges\n\
 \n\
 Print options:\n\
     PAn  - keep n largest facets by area\n\
     Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
     PDk:n - drop facet if normal[k] >= n\n\
     Pg   - print good facets (needs 'QGn' or 'QVn')\n\
     PFn  - keep facets whose area is at least n\n\
     PG   - print neighbors of good facets\n\
     PMn  - keep n facets with most merges\n\
     Po   - force output.  If error, output neighborhood of facet\n\
     Pp   - do not report precision problems\n\
 \n\
     .    - list of all options\n\
     -    - one line descriptions of all options\n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt2
     synopsis for qhull
 */
 char qh_prompt2[]= "\n\
 qhull- compute convex hulls and related structures.  Qhull %s\n\
     input (stdin): dimension, n, point coordinates\n\
     comments start with a non-numeric character\n\
     halfspace: use dim+1 and put offsets after coefficients\n\
 \n\
 options (qh-quick.htm):\n\
     d    - Delaunay triangulation by lifting points to a paraboloid\n\
     d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
     v    - Voronoi diagram as the dual of the Delaunay triangulation\n\
     v Qu - furthest-site Voronoi diagram\n\
     H1,1 - Halfspace intersection about [1,1,0,...] via polar duality\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Tv   - verify result: structure, convexity, and point inclusion\n\
     .    - concise list of all options\n\
     -    - one-line description of each option\n\
 \n\
 Output options (subset):\n\
     s    - summary of results (default)\n\
     i    - vertices incident to each facet\n\
     n    - normals with offsets\n\
     p    - vertex coordinates (if 'Qc', includes coplanar points)\n\
            if 'v', Voronoi vertices\n\
     Fp   - halfspace intersections\n\
     Fx   - extreme points (convex hull vertices)\n\
     FA   - compute total area and volume\n\
     o    - OFF format (if 'v', outputs Voronoi regions)\n\
     G    - Geomview output (2-d, 3-d and 4-d)\n\
     m    - Mathematica output (2-d and 3-d)\n\
     QVn  - print facets that include point n, -n if not\n\
     TO file- output results to file, may be enclosed in single quotes\n\
 \n\
 examples:\n\
     rbox c d D2 | qhull Qc s f Fx | more      rbox 1000 s | qhull Tv s FA\n\
     rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v Qbb Qt p\n\
     rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o\n\
     rbox c | qhull n                          rbox c | qhull FV n | qhull H Fp\n\
     rbox d D12 | qhull QR0 FA                 rbox c D7 | qhull FA TF1000\n\
     rbox y 1000 W0 | qhull                    rbox 10 | qhull v QJ o Fv\n\
 \n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt3
     concise prompt for qhull
 */
 char qh_prompt3[]= "\n\
 Qhull %s.\n\
 Except for 'F.' and 'PG', upper-case options take an argument.\n\
 \n\
  delaunay       voronoi        Geomview       Halfspace      facet_dump\n\
  incidences     mathematica    normals        OFF_format     points\n\
  summary\n\
 \n\
  Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
  FD-cdd-out     FF-dump-xridge Finner         FIDs           Fmerges\n\
  Fneighbors     FNeigh-vertex  Fouter         FOptions       Fpoint-intersect\n\
  FPoint_near    FQhull         Fsummary       FSize          Ftriangles\n\
  Fvertices      Fvoronoi       FVertex-ave    Fxtremes       FMaple\n\
 \n\
  Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
  Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
  Gtransparent\n\
 \n\
  PArea-keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
  PGood_neighbors PMerge-keep   Poutput_forced Pprecision_not\n\
 \n\
  QbBound 0:0.5  Qbk:0Bk:0_drop QbB-scale-box  Qbb-scale-last Qcoplanar\n\
  Qfurthest      Qgood_only     QGood_point    Qinterior      Qmax_out\n\
  QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
  QupperDelaunay QVertex_good   Qvneighbors    Qxact_merge    Qzinfinite\n\
 \n\
  Q0_no_premerge Q1_no_angle    Q2_no_independ Q3_no_redundant Q4_no_old\n\
  Q5_no_check_out Q6_no_concave Q7_depth_first Q8_no_near_in  Q9_pick_furthest\n\
  Q10_no_narrow  Q11_trinormals\n\
 \n\
  T4_trace       Tannotate      Tcheck_often   Tstatistics    Tverify\n\
  Tz_stdout      TFacet_log     TInput_file    TPoint_trace   TMerge_trace\n\
  TOutput_file   TRerun         TWide_trace    TVertex_stop   TCone_stop\n\
 \n\
  Angle_max      Centrum_size   Error_round    Random_dist    Visible_min\n\
  Ucoplanar_max  Wide_outside\n\
 ";
 
 /*---------------------------------
 
   main( argc, argv )
     processes the command line, calls qhull() to do the work, and exits
 
   design:
     initializes data structures
     reads points
     finishes initialization
     computes convex hull and other structures
     checks the result
     writes the output
     frees memory
 */
 int main(int argc, char *argv[]) {
   int curlong, totlong; /* used !qh_NOmem */
   int exitcode, numpoints, dim;
   coordT *points;
   boolT ismalloc;
 
 #if __MWERKS__ && __POWERPC__
   char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
   SIOUXSettings.showstatusline= false;
   SIOUXSettings.tabspaces= 1;
   SIOUXSettings.rows= 40;
   if (setvbuf(stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
   || setvbuf(stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
   || (stdout != stderr && setvbuf(stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
     fprintf(stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
   argc= ccommand(&argv);
 #endif
 
   if ((argc == 1) && isatty( 0 /*stdin*/)) {
     fprintf(stdout, qh_prompt2, qh_version);
     exit(qh_ERRnone);
   }
   if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompta, qh_version, qh_DEFAULTbox,
                 qh_promptb, qh_promptc, qh_promptd, qh_prompte);
     exit(qh_ERRnone);
   }
   if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompt3, qh_version);
     exit(qh_ERRnone);
   }
   qh_init_A(stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
   exitcode= setjmp(qh errexit); /* simple statement for CRAY J916 */
   if (!exitcode) {
     qh_initflags(qh qhull_command);
     points= qh_readpoints(&numpoints, &dim, &ismalloc);
     qh_init_B(points, numpoints, dim, ismalloc);
     qh_qhull();
     qh_check_output();
     qh_produce_output();
     if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
       qh_check_points();
     exitcode= qh_ERRnone;
   }
   qh NOerrexit= True;  /* no more setjmp */
 #ifdef qh_NOmem
   qh_freeqhull( True);
 #else
   qh_freeqhull( False);
   qh_memfreeshort(&curlong, &totlong);
   if (curlong || totlong)
     fprintf(stderr, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
        totlong, curlong);
 #endif
   return exitcode;
 } /* main */
 
diff --git a/src/qhullptest/Coordinates_test.cpp b/src/qhullptest/Coordinates_test.cpp
index bdc3589..dc31a8f 100644
--- a/src/qhullptest/Coordinates_test.cpp
+++ b/src/qhullptest/Coordinates_test.cpp
@@ -1,534 +1,534 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/Coordinates_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/Coordinates_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "Coordinates.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class Coordinates_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void t_construct();
     void t_convert();
     void t_element();
     void t_readonly();
     void t_operator();
     void t_const_iterator();
     void t_iterator();
     void t_coord_iterator();
     void t_mutable_coord_iterator();
     void t_readwrite();
     void t_search();
     void t_io();
 };//Coordinates_test
 
 void
 add_Coordinates_test()
 {
     new Coordinates_test();
 }
 
 void Coordinates_test::
 t_construct()
 {
     Coordinates c;
     QCOMPARE(c.size(), 0U);
     QVERIFY(c.isEmpty());
     c << 1.0;
     QCOMPARE(c.count(), 1);
     Coordinates c2(c);
     c2 << 2.0;
     QCOMPARE(c2.count(), 2);
     Coordinates c3;
     c3 = c2;
     QCOMPARE(c3.count(), 2);
     QCOMPARE(c3[0]+c3[1], 3.0);
     QVERIFY(c2==c3);
     std::vector vc;
     vc.push_back(3.0);
     vc.push_back(4.0);
     Coordinates c4(vc);
     QCOMPARE(c4[0]+c4[1], 7.0);
     Coordinates c5(c3);
     QVERIFY(c5==c3);
     c5= vc;
     QVERIFY(c5!=c3);
     QVERIFY(c5==c4);
 }//t_construct
 
 void Coordinates_test::
 t_convert()
 {
     Coordinates c;
     c << 1.0 << 3.0;
     QCOMPARE(c.data()[1], 3.0);
     coordT *c2= c.data();
     const coordT *c3= c.data();
     QCOMPARE(c2, c3);
     std::vector vc= c.toStdVector();
     QCOMPARE(vc.size(), c.size());
     for(size_t k= vc.size(); k--; ){
         QCOMPARE(vc[k], c[k]);
     }
     QList qc= c.toQList();
     QCOMPARE(qc.count(), c.count());
     for(int k= qc.count(); k--; ){
         QCOMPARE(qc[k], c[k]);
     }
     Coordinates c4;
     c4= std::vector(2, 0.0);
     QCOMPARE(c4.back(), 0.0);
     Coordinates c5(std::vector(2, 0.0));
     QCOMPARE(c4.size(), c5.size());
     QVERIFY(c4==c5);
 }//t_convert
 
 void Coordinates_test::
 t_element()
 {
     Coordinates c;
     c << 1.0 << -2.0;
     c.at(1)= -3;
     QCOMPARE(c.at(1), -3.0);
     QCOMPARE(c.back(), -3.0);
     QCOMPARE(c.front(), 1.0);
     c[1]= -2.0;
     QCOMPARE(c[1],-2.0);
     QCOMPARE(c.first(), 1.0);
     c.first()= 2.0;
     QCOMPARE(c.first(), 2.0);
     QCOMPARE(c.last(), -2.0);
     c.last()= 0.0;
     QCOMPARE(c.first()+c.last(), 2.0);
     coordT *c4= &c.first();
     const coordT *c5= &c.first();
     QCOMPARE(c4, c5);
     coordT *c6= &c.last();
     const coordT *c7= &c.last();
     QCOMPARE(c6, c7);
     Coordinates c2= c.mid(1);
     QCOMPARE(c2.count(), 1);
     c << 3.0;
     Coordinates c3= c.mid(1,1);
     QCOMPARE(c2, c3);
     QCOMPARE(c3.value(-1, -1.0), -1.0);
     QCOMPARE(c3.value(3, 4.0), 4.0);
     QCOMPARE(c.value(2, 4.0), 3.0);
 }//t_element
 
 void Coordinates_test::
 t_readonly()
 {
     Coordinates c;
     QCOMPARE(c.size(), 0u);
     QCOMPARE(c.count(), 0);
     QVERIFY(c.empty());
     QVERIFY(c.isEmpty());
     c << 1.0 << -2.0;
     QCOMPARE(c.size(), 2u);
     QCOMPARE(c.count(), 2);
     QVERIFY(!c.empty());
     QVERIFY(!c.isEmpty());
 }//t_readonly
 
 void Coordinates_test::
 t_operator()
 {
     Coordinates c;
     Coordinates c2(c);
     QVERIFY(c==c2);
     QVERIFY(!(c!=c2));
     c << 1.0;
     QVERIFY(!(c==c2));
     QVERIFY(c!=c2);
     c2 << 1.0;
     QVERIFY(c==c2);
     QVERIFY(!(c!=c2));
     c[0]= 0.0;
     QVERIFY(c!=c2);
     Coordinates c3= c+c2;
     QCOMPARE(c3.count(), 2);
     QCOMPARE(c3[0], 0.0);
     QCOMPARE(c3[1], 1.0);
     c3 += c3;
     QCOMPARE(c3.count(), 4);
     QCOMPARE(c3[2], 0.0);
     QCOMPARE(c3[3], 1.0);
     c3 += c2;
     QCOMPARE(c3[4], 1.0);
     c3 += 5.0;
     QCOMPARE(c3.count(), 6);
     QCOMPARE(c3[5], 5.0);
     // << checked above
 }//t_operator
 
 void Coordinates_test::
 t_const_iterator()
 {
     Coordinates c;
     QCOMPARE(c.begin(), c.end());
     // begin and end checked elsewhere
     c << 1.0 << 3.0;
     Coordinates::const_iterator i= c.begin();
     QCOMPARE(*i, 1.0);
     QCOMPARE(i[1], 3.0);
     // i[1]= -3.0; // compiler error
     // operator-> is not applicable to double
     QCOMPARE(*i++, 1.0);
     QCOMPARE(*i, 3.0);
     QCOMPARE(*i--, 3.0);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 3.0);
     QCOMPARE(*++i, 3.0);
     QCOMPARE(*(i-1), 1.0);
     QCOMPARE(*--i, 1.0);
     QVERIFY(i==c.begin());
     QVERIFY(i==c.constBegin());
     QVERIFY(i!=c.end());
     QVERIFY(i!=c.constEnd());
     QVERIFY(i=c.begin());
     QVERIFY(i+1<=c.end());
     QVERIFY(i+1>c.begin());
     Coordinates::iterator i2= c.begin();
     Coordinates::const_iterator i3(i2);
     QCOMPARE(*i3, 1.0);
     QCOMPARE(i3[1], 3.0);
 }//t_const_iterator
 
 void Coordinates_test::
 t_iterator()
 {
     Coordinates c;
     QCOMPARE(c.begin(), c.end());
     // begin and end checked elsewhere
     c << 1.0 << 3.0;
     Coordinates::iterator i= c.begin();
     QCOMPARE(*i, 1.0);
     QCOMPARE(i[1], 3.0);
     *i= -1.0;
     QCOMPARE(*i, -1.0);
     i[1]= -3.0;
     QCOMPARE(i[1], -3.0);
     *i= 1.0;
     // operator-> is not applicable to double
     QCOMPARE(*i++, 1.0);
     QCOMPARE(*i, -3.0);
     *i= 3.0;
     QCOMPARE(*i--, 3.0);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 3.0);
     QCOMPARE(*++i, 3.0);
     QCOMPARE(*(i-1), 1.0);
     QCOMPARE(*--i, 1.0);
     QVERIFY(i==c.begin());
     QVERIFY(i==c.constBegin());
     QVERIFY(i!=c.end());
     QVERIFY(i!=c.constEnd());
     QVERIFY(i=c.begin());
     QVERIFY(i+1<=c.end());
     QVERIFY(i+1>c.begin());
 }//t_iterator
 
 void Coordinates_test::
 t_coord_iterator()
 {
     Coordinates c;
     c << 1.0 << 3.0;
     CoordinatesIterator i(c);
     CoordinatesIterator i2= c;
     QVERIFY(i.findNext(1.0));
     QVERIFY(!i.findNext(2.0));
     QVERIFY(!i.findNext(3.0));
     QVERIFY(i.findPrevious(3.0));
     QVERIFY(!i.findPrevious(2.0));
     QVERIFY(!i.findPrevious(1.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(3.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(1.0));
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     Coordinates c2;
     i2= c2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekPrevious(), 3.0);
     QCOMPARE(i.previous(), 3.0);
     QCOMPARE(i.previous(), 1.0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), 1.0);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), 1.0);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.next(), 3.0);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), 1.0);
 }//t_coord_iterator
 
 void Coordinates_test::
 t_mutable_coord_iterator()
 {
     // Same tests as CoordinatesIterator
     Coordinates c;
     c << 1.0 << 3.0;
     MutableCoordinatesIterator i(c);
     MutableCoordinatesIterator i2= c;
     QVERIFY(i.findNext(1.0));
     QVERIFY(!i.findNext(2.0));
     QVERIFY(!i.findNext(3.0));
     QVERIFY(i.findPrevious(3.0));
     QVERIFY(!i.findPrevious(2.0));
     QVERIFY(!i.findPrevious(1.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(3.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(1.0));
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     Coordinates c2;
     i2= c2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekPrevious(), 3.0);
     QCOMPARE(i.peekPrevious(), 3.0);
     QCOMPARE(i.previous(), 3.0);
     QCOMPARE(i.previous(), 1.0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), 1.0);
     QCOMPARE(i.next(), 1.0);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.next(), 3.0);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), 1.0);
 
     // Mutable tests
     i.toFront();
     i.peekNext()= -1.0;
     QCOMPARE(i.peekNext(), -1.0);
     QCOMPARE((i.next()= 1.0), 1.0);
     QCOMPARE(i.peekPrevious(), 1.0);
     i.remove();
     QCOMPARE(c.count(), 1);
     i.remove();
     QCOMPARE(c.count(), 1);
     QCOMPARE(i.peekNext(), 3.0);
     i.insert(1.0);
     i.insert(2.0);
     QCOMPARE(c.count(), 3);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.peekPrevious(), 2.0);
     i.peekPrevious()= -2.0;
     QCOMPARE(i.peekPrevious(), -2.0);
     QCOMPARE((i.previous()= 2.0), 2.0);
     QCOMPARE(i.peekNext(), 2.0);
     i.toBack();
     i.remove();
     QCOMPARE(c.count(), 3); // unchanged
     i.toFront();
     i.remove();
     QCOMPARE(c.count(), 3); // unchanged
     QCOMPARE(i.peekNext(), 1.0);
     i.remove();
     QCOMPARE(c.count(), 3); // unchanged
     i.insert(0.0);
     QCOMPARE(c.count(), 4);
     QCOMPARE(i.value(), 0.0);
     QCOMPARE(i.peekPrevious(), 0.0);
     i.setValue(-10.0);
     QCOMPARE(c.count(), 4); // unchanged
     QCOMPARE(i.peekNext(), 1.0);
     QCOMPARE(i.peekPrevious(), -10.0);
     i.findNext(1.0);
     i.setValue(-1.0);
     QCOMPARE(i.peekPrevious(), -1.0);
     i.setValue(1.0);
     QCOMPARE(i.peekPrevious(), 1.0);
     QCOMPARE(i.value(), 1.0);
     i.findPrevious(1.0);
     i.setValue(-1.0);
     QCOMPARE(i.peekNext(), -1.0);
     i.toBack();
     QCOMPARE(i.previous(), 3.0);
     i.setValue(-3.0);
     QCOMPARE(i.peekNext(), -3.0);
     double d= i.value();
     QCOMPARE(d, -3.0);
     QCOMPARE(i.previous(), 2.0);
 }//t_mutable_coord_iterator
 
 void Coordinates_test::
 t_readwrite()
 {
     Coordinates c;
     c.clear();
     QCOMPARE(c.count(), 0);
     c << 1.0 << 3.0;
     c.clear();
     QCOMPARE(c.count(), 0);
     c << 1.0 << 3.0;
     c.erase(c.begin(), c.end());
     QCOMPARE(c.count(), 0);
     c << 1.0 << 0.0;
     Coordinates::iterator i= c.erase(c.begin());
     QCOMPARE(*i, 0.0);
     i= c.insert(c.end(), 1.0);
     QCOMPARE(*i, 1.0);
     QCOMPARE(c.count(), 2);
     c.pop_back();
     QCOMPARE(c.count(), 1);   // 0
     QCOMPARE(c[0], 0.0);
     c.push_back(2.0);
     QCOMPARE(c.count(), 2);
     c.append(3.0);
     QCOMPARE(c.count(), 3);   // 0, 2, 3
     QCOMPARE(c[2], 3.0);
     c.insert(0, 4.0);
     QCOMPARE(c[0], 4.0);
     QCOMPARE(c[3], 3.0);
     c.insert(c.count(), 5.0);
     QCOMPARE(c.count(), 5);   // 4, 0, 2, 3, 5
     QCOMPARE(c[4], 5.0);
     c.move(4, 0);
     QCOMPARE(c.count(), 5);   // 5, 4, 0, 2, 3
     QCOMPARE(c[0], 5.0);
     c.pop_front();
     QCOMPARE(c.count(), 4);
     QCOMPARE(c[0], 4.0);
     c.prepend(6.0);
     QCOMPARE(c.count(), 5);   // 6, 4, 0, 2, 3
     QCOMPARE(c[0], 6.0);
     c.push_front(7.0);
     QCOMPARE(c.count(), 6);
     QCOMPARE(c[0], 7.0);
     c.removeAt(1);
     QCOMPARE(c.count(), 5);   // 7, 4, 0, 2, 3
     QCOMPARE(c[1], 4.0);
     c.removeFirst();
     QCOMPARE(c.count(), 4);   // 4, 0, 2, 3
     QCOMPARE(c[0], 4.0);
     c.removeLast();
     QCOMPARE(c.count(), 3);
     QCOMPARE(c.last(), 2.0);
     c.replace(2, 8.0);
     QCOMPARE(c.count(), 3);   // 4, 0, 8
     QCOMPARE(c[2], 8.0);
     c.swap(0, 2);
     QCOMPARE(c[2], 4.0);
     double d= c.takeAt(2);
     QCOMPARE(c.count(), 2);   // 8, 0
     QCOMPARE(d, 4.0);
     double d2= c.takeFirst();
     QCOMPARE(c.count(), 1);   // 0
     QCOMPARE(d2, 8.0);
     double d3= c.takeLast();
     QVERIFY(c.isEmpty()); \
     QCOMPARE(d3, 0.0);
 }//t_readwrite
 
 void Coordinates_test::
 t_search()
 {
     Coordinates c;
     c << 1.0 << 3.0 << 1.0;
     QVERIFY(c.contains(1.0));
     QVERIFY(c.contains(3.0));
     QVERIFY(!c.contains(0.0));
     QCOMPARE(c.count(1.0), 2);
     QCOMPARE(c.count(3.0), 1);
     QCOMPARE(c.count(0.0), 0);
     QCOMPARE(c.indexOf(1.0), 0);
     QCOMPARE(c.indexOf(3.0), 1);
     QCOMPARE(c.indexOf(1.0, -1), 2);
     QCOMPARE(c.indexOf(3.0, -1), -1);
     QCOMPARE(c.indexOf(3.0, -2), 1);
     QCOMPARE(c.indexOf(1.0, -3), 0);
     QCOMPARE(c.indexOf(1.0, -4), 0);
     QCOMPARE(c.indexOf(1.0, 1), 2);
     QCOMPARE(c.indexOf(3.0, 2), -1);
     QCOMPARE(c.indexOf(1.0, 2), 2);
     QCOMPARE(c.indexOf(1.0, 3), -1);
     QCOMPARE(c.indexOf(1.0, 4), -1);
     QCOMPARE(c.lastIndexOf(1.0), 2);
     QCOMPARE(c.lastIndexOf(3.0), 1);
     QCOMPARE(c.lastIndexOf(1.0, -1), 2);
     QCOMPARE(c.lastIndexOf(3.0, -1), 1);
     QCOMPARE(c.lastIndexOf(3.0, -2), 1);
     QCOMPARE(c.lastIndexOf(1.0, -3), 0);
     QCOMPARE(c.lastIndexOf(1.0, -4), -1);
     QCOMPARE(c.lastIndexOf(1.0, 1), 0);
     QCOMPARE(c.lastIndexOf(3.0, 2), 1);
     QCOMPARE(c.lastIndexOf(1.0, 2), 2);
     QCOMPARE(c.lastIndexOf(1.0, 3), 2);
     QCOMPARE(c.lastIndexOf(1.0, 4), 2);
     c.removeAll(3.0);
     QCOMPARE(c.count(), 2);
     c.removeAll(4.0);
     QCOMPARE(c.count(), 2);
     c.removeAll(1.0);
     QCOMPARE(c.count(), 0);
     c.removeAll(4.0);
     QCOMPARE(c.count(), 0);
 }//t_search
 
 void Coordinates_test::
 t_io()
 {
     Coordinates c;
     c << 1.0 << 2.0 << 3.0;
     ostringstream os;
     os << "Coordinates 1-2-3\n" << c;
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("2"), 2);
 }//t_io
 
 }//orgQhull
 
 #include "moc/Coordinates_test.moc"
diff --git a/src/qhullptest/PointCoordinates_test.cpp b/src/qhullptest/PointCoordinates_test.cpp
index 67d5ec3..03c6ba6 100644
--- a/src/qhullptest/PointCoordinates_test.cpp
+++ b/src/qhullptest/PointCoordinates_test.cpp
@@ -1,397 +1,397 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/PointCoordinates_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/PointCoordinates_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "PointCoordinates.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 using std::stringstream;
 
 namespace orgQhull {
 
 class PointCoordinates_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void t_construct();
     void t_convert();
     void t_getset();
     void t_element();
     void t_foreach();
     void t_search();
     void t_modify();
     void t_append_points();
     void t_coord_iterator();
     void t_io();
 };//PointCoordinates_test
 
 void
 add_PointCoordinates_test()
 {
     new PointCoordinates_test();
 }
 
 void PointCoordinates_test::
 t_construct()
 {
     PointCoordinates pc;
     QCOMPARE(pc.size(), 0U);
     QCOMPARE(pc.coordinateCount(), 0);
     QCOMPARE(pc.dimension(), 0);
     QCOMPARE(pc.coordinates(), (coordT *)0);
     QVERIFY(pc.isEmpty());
     pc.checkValid();
     PointCoordinates pc7(2);
     QCOMPARE(pc7.dimension(), 2);
     QCOMPARE(pc7.count(), 0);
     QVERIFY(pc7.isEmpty());
     QVERIFY(pc7.comment().empty());
     pc7.checkValid();
     PointCoordinates pc2("Test pc2");
     QCOMPARE(pc2.count(), 0);
     QVERIFY(pc2.isEmpty());
     QCOMPARE(pc2.comment(), std::string("Test pc2"));
     pc2.checkValid();
     PointCoordinates pc3(3, "Test 3-d pc3");
     QCOMPARE(pc3.dimension(), 3);
     QVERIFY(pc3.isEmpty());
     pc3.checkValid();
     coordT c[]= { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };
     PointCoordinates pc4(2, "Test 2-d pc4", 6, c);
     QCOMPARE(pc4.dimension(), 2);
     QCOMPARE(pc4.count(), 3);
     QCOMPARE(pc4.size(), 3u);
     QVERIFY(!pc4.isEmpty());
     QVERIFY(!pc4.empty());
     pc4.checkValid();
     QhullPoint p= pc4[2];
     QCOMPARE(p[1], 5.0);
     // QhullPoint refers to PointCoordinates
     p[1] += 1.0;
     QCOMPARE(pc4[2][1], 6.0);
     PointCoordinates pc5(4, "Test 4-d pc5 with insufficient coordinates", 6, c);
     QCOMPARE(pc5.dimension(), 4);
     QCOMPARE(pc5.count(), 1);
     QCOMPARE(pc5.extraCoordinatesCount(), 2);
     QCOMPARE(pc5.extraCoordinates()[1], 5.0);
     QVERIFY(!pc5.isEmpty());;
     std::vector vc;
     vc.push_back(3.0);
     vc.push_back(4.0);
     vc.push_back(5.0);
     vc.push_back(6.0);
     vc.push_back(7.0);
     vc.push_back(9.0);
     pc5.append(2, &vc[3]); // Copy of vc[]
     pc5.checkValid();
     QhullPoint p5(4, &vc[1]);
     QCOMPARE(pc5[1], p5);
     PointCoordinates pc6(pc5); // Makes copy of point_coordinates
     QCOMPARE(pc6[1], p5);
     QVERIFY(pc6==pc5);
     QhullPoint p6= pc5[1];  // Refers to pc5.coordinates
     pc5[1][0] += 1.0;
     QCOMPARE(pc5[1], p6);
     QVERIFY(pc5[1]!=p5);
     QVERIFY(pc6!=pc5);
     pc6= pc5;
     QVERIFY(pc6==pc5);
     PointCoordinates pc8;
     pc6= pc8;
     QVERIFY(pc6!=pc5);
     QVERIFY(pc6.isEmpty());
 }//t_construct
 
 void PointCoordinates_test::
 t_convert()
 {
     //defineAs tested above
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     PointCoordinates ps(3, "two 3-d points", 6, c);
     QCOMPARE(ps.dimension(), 3);
     QCOMPARE(ps.size(), 2u);
     const coordT *c2= ps.constData();
     QVERIFY(c!=c2);
     QCOMPARE(c[0], c2[0]);
     const coordT *c3= ps.data();
     QCOMPARE(c3, c2);
     coordT *c4= ps.data();
     QCOMPARE(c4, c2);
     std::vector vs= ps.toStdVector();
     QCOMPARE(vs.size(), 6u);
     QCOMPARE(vs[5], 5.0);
     QList qs= ps.toQList();
     QCOMPARE(qs.size(), 6);
     QCOMPARE(qs[5], 5.0);
 }//t_convert
 
 void PointCoordinates_test::
 t_getset()
 {
     // See t_construct() for test of coordinates, coordinateCount, dimension, empty, isEmpty, ==, !=
     // See t_construct() for test of checkValid, comment, setDimension
     PointCoordinates pc("Coordinates c");
     pc.setComment("New comment");
     QCOMPARE(pc.comment(), std::string("New comment"));
     pc.checkValid();
     pc.makeValid();  // A no-op
     pc.checkValid();
     Coordinates cs= pc.getCoordinates();
     QVERIFY(cs.isEmpty());
     PointCoordinates pc2(pc);
     pc.setDimension(3);
     QVERIFY(pc2!=pc);
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     pc.append(6, c);
     pc.checkValid();
     pc.makeValid();  // A no-op
     QhullPoint p= pc[0];
     QCOMPARE(p[2], 2.0);
     try{
         pc.setDimension(2);
         QFAIL("setDimension(2) did not fail for 3-d.");
     }catch (const std::exception &e) {
         const char *s= e.what();
         cout << "INFO   : Caught " << s;
     }
 }//t_getset
 
 void PointCoordinates_test::
 t_element()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     PointCoordinates pc(2, "2-d points", 6, c);
     QhullPoint p= pc.at(0);
     QCOMPARE(p, pc[0]);
     QCOMPARE(p, pc.first());
     QCOMPARE(p, pc.value(0));
     p= pc.back();
     QCOMPARE(p, pc[2]);
     QCOMPARE(p, pc.last());
     QCOMPARE(p, pc.value(2));
     QhullPoints ps= pc.mid(1, 2);
     QCOMPARE(ps[1], p);
 }//t_element
 
 void PointCoordinates_test::
 t_foreach()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     PointCoordinates pc(2, "2-d points", 6, c);
     QhullPoints::Iterator i= pc.begin();
     QhullPoint p= pc[0];
     QCOMPARE(*i, p);
     QCOMPARE((*i)[0], 0.0);
     QhullPoint p3= pc[2];
     i= pc.end();
     QCOMPARE(i[-1], p3);
     const PointCoordinates pc2(2, "2-d points", 6, c);
     QhullPoints::ConstIterator i2= pc.begin();
     const QhullPoint p0= pc2[0];
     QCOMPARE(*i2, p0);
     QCOMPARE((*i2)[0], 0.0);
     QhullPoints::ConstIterator i3= i2;
     QCOMPARE(i3, i2);
     QCOMPARE((*i3)[0], 0.0);
     i3= pc.constEnd();
     --i3;
     QhullPoint p2= pc2[2];
     QCOMPARE(*i3, p2);
     i= pc.end();
     QVERIFY(i-1==i3);
     i2= pc2.end();
     QVERIFY(i2-1!=i3);
     QCOMPARE(*(i2-1), *i3);
     foreach(QhullPoint p3, pc){ //Qt only
         QVERIFY(p3[0]>=0.0);
         QVERIFY(p3[0]<=5.0);
     }
     Coordinates::ConstIterator i4= pc.beginCoordinates();
     QCOMPARE(*i4, 0.0);
     Coordinates::Iterator i5= pc.beginCoordinates();
     QCOMPARE(*i5, 0.0);
     i4= pc.beginCoordinates(1);
     QCOMPARE(*i4, 2.0);
     i5= pc.beginCoordinates(1);
     QCOMPARE(*i5, 2.0);
     i4= pc.endCoordinates();
     QCOMPARE(*--i4, 5.0);
     i5= pc.endCoordinates();
     QCOMPARE(*--i5, 5.0);
 }//t_foreach
 
 void PointCoordinates_test::
 t_search()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     PointCoordinates pc(2, "2-d points", 6, c);
     QhullPoint p0= pc[0];
     QhullPoint p2= pc[2];
     QVERIFY(pc.contains(p0));
     QVERIFY(pc.contains(p2));
     QCOMPARE(pc.count(p0), 1);
     QCOMPARE(pc.indexOf(p2), 2);
     QCOMPARE(pc.lastIndexOf(p0), 0);
 }//t_search
 
 void PointCoordinates_test::
 t_modify()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     PointCoordinates pc(2, "2-d points", 6, c);
     coordT c3[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     PointCoordinates pc5(2);
     pc5.append(6, c3); // 0-5
     QVERIFY(pc5==pc);
     PointCoordinates pc2(2, "2-d");
     coordT c2[]= {6.0, 7.0, 8.0, 9.0, 10.0, 11.0};
     pc2.append(6, c2);
     QCOMPARE(pc2.count(), 3);
     pc2.append(14.0);
     QCOMPARE(pc2.count(), 3);
     QCOMPARE(pc2.extraCoordinatesCount(), 1);
     pc2.append(15.0); // 6-11, 14,15
     QCOMPARE(pc2.count(), 4);
     QCOMPARE(pc2.extraCoordinatesCount(), 0);
     QhullPoint p(pc[0]);
     pc2.append(p); // 6-11, 14,15, 0,1
     QCOMPARE(pc2.count(), 5);
     QCOMPARE(pc2.extraCoordinatesCount(), 0);
     QCOMPARE(pc2.lastIndexOf(p), 4);
     pc.append(pc2); // Invalidates p
     QCOMPARE(pc.count(), 8); // 0-11, 14,15, 0,1
     QCOMPARE(pc.extraCoordinatesCount(), 0);
     QCOMPARE(pc.lastIndexOf(pc[0]), 7);
     pc.appendComment(" operators");
     QCOMPARE(pc.comment(), std::string("2-d points operators"));
     pc.checkValid();
     // see t_append_points for appendPoints
     PointCoordinates pc3= pc+pc2;
     pc3.checkValid();
     QCOMPARE(pc3.count(), 13);
     QCOMPARE(pc3[6][0], 14.0);
     QCOMPARE(pc3[8][0], 6.0);
     pc3 += pc;
     QCOMPARE(pc3.count(), 21);
     QCOMPARE(pc3[14][0], 2.0);
     pc3 += 12.0;
     pc3 += 14.0;
     QCOMPARE(pc3.count(), 22);
     QCOMPARE(pc3.last()[0], 12.0);
     // QhullPoint p3= pc3.first(); // += throws error because append may move the data
     QhullPoint p3= pc2.first();
     pc3 += p3;
     QCOMPARE(pc3.count(), 23);
     QCOMPARE(pc3.last()[0], 6.0);
     pc3 << pc;
     QCOMPARE(pc3.count(), 31);
     QCOMPARE(pc3.last()[0], 0.0);
     pc3 << 12.0 << 14.0;
     QCOMPARE(pc3.count(), 32);
     QCOMPARE(pc3.last()[0], 12.0);
     PointCoordinates pc4(pc3);
     pc4.reserveCoordinates(100);
     QVERIFY(pc3==pc4);
 }//t_modify
 
 void PointCoordinates_test::
 t_append_points()
 {
     PointCoordinates pc(2, "stringstream");
     stringstream s("2 3 1 2 3 4 5 6");
     pc.appendPoints(s);
     QCOMPARE(pc.count(), 3);
 }//t_append_points
 
 void PointCoordinates_test::
 t_coord_iterator()
 {
     PointCoordinates c(2);
     c << 0.0 << 1.0 << 2.0 << 3.0 << 4.0 << 5.0;
     PointCoordinatesIterator i(c);
     QhullPoint p0(c[0]);
     QhullPoint p1(c[1]);
     QhullPoint p2(c[2]);
     coordT c2[] = {-1.0, -2.0};
     QhullPoint p3(2, c2);
     PointCoordinatesIterator i2= c;
     QVERIFY(i.findNext(p1));
     QVERIFY(!i.findNext(p1));
     QVERIFY(!i.findNext(p2));
     QVERIFY(!i.findNext(p3));
     QVERIFY(i.findPrevious(p2));
     QVERIFY(!i.findPrevious(p2));
     QVERIFY(!i.findPrevious(p0));
     QVERIFY(!i.findPrevious(p3));
     QVERIFY(i2.findNext(p2));
     QVERIFY(i2.findPrevious(p0));
     QVERIFY(i2.findNext(p1));
     QVERIFY(i2.findPrevious(p0));
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     PointCoordinates c3;
     PointCoordinatesIterator i3= c3;
     QVERIFY(!i3.hasNext());
     QVERIFY(!i3.hasPrevious());
     i3.toBack();
     QVERIFY(!i3.hasNext());
     QVERIFY(!i3.hasPrevious());
     QCOMPARE(i.peekPrevious(), p2);
     QCOMPARE(i.previous(), p2);
     QCOMPARE(i.previous(), p1);
     QCOMPARE(i.previous(), p0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), p0);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), p0);
     QCOMPARE(i.peekNext(), p1);
     QCOMPARE(i.next(), p1);
     QCOMPARE(i.next(), p2);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p0);
 }//t_coord_iterator
 
 void PointCoordinates_test::
 t_io()
 {
     PointCoordinates c;
     c << 1.0 << 2.0 << 3.0 << 1.0 << 2.0 << 3.0;
     ostringstream os;
     os << "PointCoordinates 0-d\n" << c;
     c.setDimension(2);
     os << "PointCoordinates 1-3-2\n" << c;
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("0"), 3);
     QCOMPARE(s.count("2"), 4);
 }//t_io
 
 }//orgQhull
 
 #include "moc/PointCoordinates_test.moc"
diff --git a/src/qhullptest/Point_test.cpp b/src/qhullptest/Point_test.cpp
index 430c721..ab3d1b7 100644
--- a/src/qhullptest/Point_test.cpp
+++ b/src/qhullptest/Point_test.cpp
@@ -1,238 +1,238 @@
 /****************************************************************************
 **
-** Copyright (C) 2009-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/Point_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (C) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/Point_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include 
 using std::cout;
 using std::endl;
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullPoint.h"
 
 #include "Qhull.h"
 
 namespace orgQhull {
 
 class Point_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void initTestCase();
     void t_construct();
     void t_getset();
     void t_operator();
     void t_const_iterator();
     void t_iterator();
     void t_point_iterator();
     // void t_mutable_point_iterator();
     // void t_io();
 };//Point_test
 
 void
 add_Point_test()
 {
     new Point_test();
 }
 
 void Point_test::
 initTestCase(){
     RboxPoints rcube("c");
     Qhull q(rcube, "");
     UsingQhullLib::setGlobals();
 }//initTestCase
 
 void Point_test::
 t_construct()
 {
     QhullPoint p;
     QCOMPARE(p.dimension(), 0);
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoint p2;
     p2.defineAs(3, c);
     QCOMPARE(p2.dimension(), 3);
     QCOMPARE(p2.coordinates(), c);
     coordT c2[]= {0.0, 1.0, 2.0};
     QhullPoint p3(3, c2);
     QVERIFY(p3==p2);
     QhullPoint p5(p3);
     QVERIFY(p5==p3);
 }//t_construct
 
 void Point_test::
 t_getset()
 {
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoint p(3, c);
     QCOMPARE(p.coordinates(), c);
     QCOMPARE(p.dimension(), 3);
     QCOMPARE(p[2], 2.0);
     QhullPoint p2(p);
     p2.defineAs(p);
     QVERIFY(p2==p);
     QVERIFY(p2.coordinates()==p.coordinates());
     QVERIFY(p2.dimension()==p.dimension());
     p2.setDimension(2);
     QCOMPARE(p2.dimension(), 2);
     QVERIFY(p2!=p);
     coordT c2[]= {0.0, 1.0};
     p2.setCoordinates(c2);
     QCOMPARE(p2.coordinates(), c2);
     p.defineAs(2, c);
     QVERIFY(p2==p);
     QCOMPARE(p[1], 1.0);
 }//t_getset
 
 void Point_test::
 t_operator()
 {
     QhullPoint p;
     QhullPoint p2(p);
     QVERIFY(p==p2);
     QVERIFY(!(p!=p2));
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoint p3(3, c);
     QVERIFY(p3!=p2);
     QhullPoint p4(p3);
     QVERIFY(p4==p3);
     coordT c5[]= {5.0, 6.0, 7.0};
     QhullPoint p5(3, c5);
     QVERIFY(p5!=p3);
     QCOMPARE(p5[1], 6.0);
     QCOMPARE(p5[0], 5.0);
     const coordT *c0= &p5[0];
     QCOMPARE(*c0, 5.0);
 }//t_operator
 
 void Point_test::
 t_const_iterator()
 {
     coordT c[]= {1.0, 2.0, 3.0};
     QhullPoint p(3, c);
     QhullPoint::const_iterator i(p.coordinates());
     QhullPoint::const_iterator i2= p.coordinates();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 2.0);
     QCOMPARE(*(i+1), i[1]);
     i= p.end();
     QVERIFY(i!=i2);
     i= i2;
     QVERIFY(i==i2);
     i= p.end();
     i= p.begin();
     QCOMPARE(*i, 1.0);
     QhullPoint::ConstIterator i3= p.end();
     QCOMPARE(*(i3-1), 3.0);
     QCOMPARE(*(i3-1), i3[-1]);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
 }//t_const_iterator
 
 
 void Point_test::
 t_iterator()
 {
     coordT c[]= {1.0, 2.0, 3.0};
     QhullPoint p(3, c);
     QhullPoint::Iterator i(p.coordinates());
     QhullPoint::iterator i2= p.coordinates();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 2.0);
     QCOMPARE(*(i+1), i[1]);
     i= p.end();
     QVERIFY(i!=i2);
     i= i2;
     QVERIFY(i==i2);
     i= p.end();
     i= p.begin();
     QCOMPARE(*i, 1.0);
     QhullPoint::Iterator i3= p.end();
     QCOMPARE(*(i3-1), 3.0);
     QCOMPARE(*(i3-1), i3[-1]);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
     // compiler errors -- QhullPoint is const-only
     // QCOMPARE((i[0]= -10.0), -10.0);
     // coordT *c3= &i3[1];
 }//t_iterator
 
 void Point_test::
 t_point_iterator()
 {
     coordT c[]= {1.0, 3.0, 4.0};
     QhullPoint p(3, c);
     QhullPointIterator i(p);
     QhullPointIterator i2= p;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
 
     coordT c2[]= {1.0, 3.0, 4.0};
     QhullPoint p2(0, c2); // 0-dimensional
     i2= p2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekPrevious(), 4.0);
     QCOMPARE(i.previous(), 4.0);
     QCOMPARE(i.previous(), 3.0);
     QCOMPARE(i.previous(), 1.0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), 1.0);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), 1.0);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.next(), 3.0);
     QCOMPARE(i.next(), 4.0);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), 1.0);
 }//t_point_iterator
 
 // No MutableQhullPointIterator since QhullPoint is const-only
 
 #if 0
 
 void Point_test::
 t_io()
 {
     QhullPoint p;
     cout<< "INFO:     empty point" << p << endl;
     const coordT c[]= {1.0, 3.0, 4.0};
     QhullPoint p2(2, c); // 2-dimensional
     cout<< "INFO:   " << p2 << endl;
 }//t_io
 
 error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class orgQhull::QhullPoint &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAVPoint@orgQhull@@@Z) referenced in function "private: void __thiscall orgQhull::Point_test::t_io(void)" (?t_io@Point_test@orgQhull@@AAEXXZ)
 
 #endif
 
 }//orgQhull
 
 #include "moc/Point_test.moc"
diff --git a/src/qhullptest/QhullFacetList_test.cpp b/src/qhullptest/QhullFacetList_test.cpp
index 2722f37..39f7bcb 100644
--- a/src/qhullptest/QhullFacetList_test.cpp
+++ b/src/qhullptest/QhullFacetList_test.cpp
@@ -1,172 +1,172 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullFacetList_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullFacetList_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullFacetList.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "QhullVertexSet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacetList_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_foreach();
     void t_io();
 };//QhullFacetList_test
 
 void
 add_QhullFacetList_test()
 {
     new QhullFacetList_test();
 }
 
 //Executed after each testcase
 void QhullFacetList_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullFacetList_test::
 t_construct()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacetList fs2= q.facetList();
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),6);
     QhullFacetList fs3(q.endFacet(), q.endFacet());
     QVERIFY(fs3.isEmpty());
     QhullFacetList fs4(q.endFacet().previous(), q.endFacet());
     QCOMPARE(fs4.count(), 1);
     QhullFacetList fs5(q.beginFacet(), q.endFacet());
     QCOMPARE(fs2.count(), fs5.count());
     QVERIFY(fs2==fs5);
     QhullFacetList fs6= fs2; // copy constructor
     QVERIFY(fs6==fs2);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 6u);
 }//t_construct
 
 void QhullFacetList_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0 QV2");  // rotated unit cube
     QhullFacetList fs2= q.facetList();
     QVERIFY(!fs2.isSelectAll());
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),3);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 3u);
     QList fv2= fs2.toQList();
     QCOMPARE(fv2.size(), 3);
     std::vector fv5= fs2.vertices_toStdVector(q.runId());
     QCOMPARE(fv5.size(), 7u);
     QList fv6= fs2.vertices_toQList(q.runId());
     QCOMPARE(fv6.size(), 7);
     fs2.selectAll();
     QVERIFY(fs2.isSelectAll());
     std::vector fv3= fs2.toStdVector();
     QCOMPARE(fv3.size(), 6u);
     QList fv4= fs2.toQList();
     QCOMPARE(fv4.size(), 6);
     std::vector fv7= fs2.vertices_toStdVector(q.runId());
     QCOMPARE(fv7.size(), 8u);
     QList fv8= fs2.vertices_toQList(q.runId());
     QCOMPARE(fv8.size(), 8);
 }//t_convert
 
 //! Spot check properties and read-only.  See QhullLinkedList_test
 void QhullFacetList_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
     QhullFacetList fs= q.facetList();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 3);
     QCOMPARE(fs.first(), q.firstFacet());
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 6);
     fs.selectGood();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 3);
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 6);
     QhullFacet f= fs.first();
     QhullFacet f2= fs.last();
     fs.selectAll();
     QVERIFY(fs.contains(f));
     QVERIFY(fs.contains(f2));
     QVERIFY(f.isGood());
     QVERIFY(!f2.isGood());
     fs.selectGood();
     QVERIFY(fs.contains(f));
     QVERIFY(!fs.contains(f2));
 }//t_readonly
 
 void QhullFacetList_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     // Spot check predicates and accessors.  See QhullLinkedList_test
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullFacetList fs= q.facetList();
     QVERIFY(fs.contains(q.firstFacet()));
     QhullFacet f= q.firstFacet().next();
     QVERIFY(fs.contains(f));
     QCOMPARE(fs.first(), *fs.begin());
     QCOMPARE(*(fs.end()-1), fs.last());
     QCOMPARE(fs.first(), q.firstFacet());
     QCOMPARE(*fs.begin(), q.beginFacet());
     QCOMPARE(*fs.end(), q.endFacet());
 }//t_foreach
 
 void QhullFacetList_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
         QhullFacetList fs= q.facetList();
         ostringstream os;
         os << fs.print(q.runId()); // Runs all print options
         os << "\nFacets only\n" << fs; // printVertices() requires a runId
         cout << os.str();
         QString facets= QString::fromStdString(os.str());
         QCOMPARE(facets.count("(v"), 7+12*3*2);
         QCOMPARE(facets.count(QRegExp("f\\d")), 3*7 + 13*3*2);
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullFacetList_test.moc"
diff --git a/src/qhullptest/QhullFacetSet_test.cpp b/src/qhullptest/QhullFacetSet_test.cpp
index b3b84c3..bdf421f 100644
--- a/src/qhullptest/QhullFacetSet_test.cpp
+++ b/src/qhullptest/QhullFacetSet_test.cpp
@@ -1,153 +1,153 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullFacetSet_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullFacetSet_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullFacetSet.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacetSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_foreach();
     void t_io();
 };//QhullFacetSet_test
 
 void
 add_QhullFacetSet_test()
 {
     new QhullFacetSet_test();
 }
 
 //Executed after each testcase
 void QhullFacetSet_test::
 cleanup()
 {
     RoadTest::cleanup();
     UsingLibQhull::checkQhullMemoryEmpty();
 }
 
 void QhullFacetSet_test::
 t_construct()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullFacetSet fs2= f.neighborFacets();
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),4);
     QhullFacetSet fs4= fs2; // copy constructor
     QVERIFY(fs4==fs2);
     QhullFacetSet fs3(q.qhullQh()->facet_mergeset);
     QVERIFY(fs3.isEmpty());
 }//t_construct
 
 void QhullFacetSet_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q2(rcube,"QR0 QV2");  // rotated unit cube
     QhullFacet f2= q2.firstFacet();
     QhullFacetSet fs2= f2.neighborFacets();
     QVERIFY(!fs2.isSelectAll());
     QCOMPARE(fs2.count(),2);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 2u);
     QList fv2= fs2.toQList();
     QCOMPARE(fv2.size(), 2);
     fs2.selectAll();
     QVERIFY(fs2.isSelectAll());
     std::vector fv3= fs2.toStdVector();
     QCOMPARE(fv3.size(), 4u);
     QList fv4= fs2.toQList();
     QCOMPARE(fv4.size(), 4);
 }//t_convert
 
 //! Spot check properties and read-only.  See QhullSet_test
 void QhullFacetSet_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 4);
     fs.selectGood();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     QhullFacet f= fs.first();
     QhullFacet f2= fs.last();
     fs.selectAll();
     QVERIFY(fs.contains(f));
     QVERIFY(fs.contains(f2));
     QVERIFY(f.isGood());
     QVERIFY(!f2.isGood());
     fs.selectGood();
     QVERIFY(fs.contains(f));
     QVERIFY(!fs.contains(f2));
 }//t_readonly
 
 void QhullFacetSet_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     // Spot check predicates and accessors.  See QhullLinkedList_test
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.contains(q.firstFacet()));
     QVERIFY(fs.contains(fs.first()));
     QhullFacet f= q.firstFacet().next();
     if(!fs.contains(f)){
         f= f.next();
     }
     QVERIFY(fs.contains(f));
     QCOMPARE(fs.first(), *fs.begin());
     QCOMPARE(*(fs.end()-1), fs.last());
 }//t_foreach
 
 void QhullFacetSet_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
         QhullFacetSet fs= q.firstFacet().neighborFacets();
         ostringstream os;
         os << fs.print(q.runId(), "Neighbors of first facet with point 0");
         os << fs.printIdentifiers("\nFacet identifiers: ");
         cout << os.str();
         QString facets= QString::fromStdString(os.str());
         QCOMPARE(facets.count(QRegExp(" f[0-9]")), 2+13*2);
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullFacetSet_test.moc"
diff --git a/src/qhullptest/QhullFacet_test.cpp b/src/qhullptest/QhullFacet_test.cpp
index 81082bd..4305318 100644
--- a/src/qhullptest/QhullFacet_test.cpp
+++ b/src/qhullptest/QhullFacet_test.cpp
@@ -1,264 +1,264 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullFacet_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullFacet_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullFacet.h"
 #include "QhullError.h"
 #include "Coordinates.h"
 #include "RboxPoints.h"
 #include "QhullFacetList.h"
 #include "QhullFacetSet.h"
 #include "QhullPointSet.h"
 #include "QhullRidge.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_constructConvert();
     void t_getSet();
     void t_value();
     void t_foreach();
     void t_io();
 };//QhullFacet_test
 
 void
 add_QhullFacet_test()
 {
     new QhullFacet_test();
 }
 
 //Executed after each testcase
 void QhullFacet_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullFacet_test::
 t_constructConvert()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullFacet f;
     QVERIFY(!f.isDefined());
     QCOMPARE(f.dimension(),0);
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullFacet f2(q.beginFacet());
     QCOMPARE(f2.dimension(),3);
     f= f2; // copy assignment
     QVERIFY(f.isDefined());
     QCOMPARE(f.dimension(),3);
     QhullFacet f5= f2;
     QVERIFY(f5==f2);
     QVERIFY(f5==f);
     QhullFacet f3= f2.getFacetT();
     QCOMPARE(f,f3);
     QhullFacet f4= f2.getBaseT();
     QCOMPARE(f,f4);
 }//t_constructConvert
 
 void QhullFacet_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QCOMPARE(q.vertexCount(), 8);
         QhullFacetListIterator i(q.facetList());
         while(i.hasNext()){
             const QhullFacet f= i.next();
             cout << f.id() << endl;
             QCOMPARE(f.dimension(),3);
             QVERIFY(f.id()>0 && f.id()<=39);
             QVERIFY(f.isDefined());
             if(i.hasNext()){
                 QCOMPARE(f.next(), i.peekNext());
                 QVERIFY(f.next()!=f);
             }
             QVERIFY(i.hasPrevious());
             QCOMPARE(f, i.peekPrevious());
         }
         QhullFacetListIterator i2(i);
         QEXPECT_FAIL("", "ListIterator copy constructor not reset to BOT", Continue);
         QVERIFY(!i2.hasPrevious());
 
         // test tricoplanarOwner
         QhullFacet facet = q.beginFacet();
         QhullFacet tricoplanarOwner = facet.tricoplanarOwner();
         int tricoplanarCount= 0;
         i.toFront();
         while(i.hasNext()){
             const QhullFacet f= i.next();
             if(f.tricoplanarOwner()==tricoplanarOwner){
                 tricoplanarCount++;
             }
         }
         QCOMPARE(tricoplanarCount, 2);
         int tricoplanarCount2= 0;
         foreach (QhullFacet f, q.facetList()){  // Qt only
             QhullHyperplane h= f.hyperplane();
             cout << "Hyperplane: " << h << endl;
             QCOMPARE(h.count(), 3);
             QCOMPARE(h.offset(), -0.5);
             double n= h.norm();
             QCOMPARE(n, 1.0);
             QhullHyperplane hi= f.innerplane(q.runId());
             QCOMPARE(hi.count(), 3);
             double innerOffset= hi.offset()+0.5;
             cout << "InnerPlane: " << hi << "innerOffset+0.5 " << innerOffset << endl;
             QVERIFY(innerOffset >= 0.0);
             QhullHyperplane ho= f.outerplane(q.runId());
             QCOMPARE(ho.count(), 3);
             double outerOffset= ho.offset()+0.5;
             cout << "OuterPlane: " << ho << "outerOffset+0.5 " << outerOffset << endl;
             QVERIFY(outerOffset <= 0.0);
             QVERIFY(outerOffset-innerOffset < 1e-7);
             for(int k= 0; k<3; k++){
                 QVERIFY(ho[k]==hi[k]);
                 QVERIFY(ho[k]==h[k]);
             }
             QhullPoint center= f.getCenter(q.runId());
             cout << "Center: " << center << endl;
             double d= f.distance(center);
             QVERIFY(d < innerOffset-outerOffset);
             QhullPoint center2= f.getCenter(q.runId(), qh_PRINTcentrums);
             QCOMPARE(center, center2);
             if(f.tricoplanarOwner()==tricoplanarOwner){
                 tricoplanarCount2++;
             }
         }
         QCOMPARE(tricoplanarCount2, 2);
         Qhull q2(rcube,"d Qz Qt QR0");  // 3-d triangulation of Delaunay triangulation (the cube)
         QhullFacet f2= q2.firstFacet();
         QhullPoint center3= f2.getCenter(q.runId(), qh_PRINTtriangles);
         QCOMPARE(center3.dimension(), 3);
         QhullPoint center4= f2.getCenter(q.runId());
         QCOMPARE(center4.dimension(), 3);
         for(int k= 0; k<3; k++){
             QVERIFY(center4[k]==center3[k]);
         }
         Qhull q3(rcube,"v Qz QR0");  // Voronoi diagram of a cube (one vertex)
 
         UsingLibQhull::setGlobalDistanceEpsilon(1e-12); // Voronoi vertices are not necessarily within distance episilon
         foreach(QhullFacet f, q3.facetList()){ //Qt only
             if(f.isGood()){
                 QhullPoint p= f.voronoiVertex(q3.runId());
                 cout << p.print(q3.runId(), "Voronoi vertex: ")
                     << " DistanceEpsilon " << UsingLibQhull::globalDistanceEpsilon() << endl;
                 QCOMPARE(p, q3.origin());
             }
         }
     }
 }//t_getSet
 
 void QhullFacet_test::
 t_value()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         coordT c[]= {0.0, 0.0, 0.0};
         foreach (QhullFacet f, q.facetList()){  // Qt only
             double d= f.distance(q.origin());
             QCOMPARE(d, -0.5);
             double d0= f.distance(c);
             QCOMPARE(d0, -0.5);
             double facetArea= f.facetArea(q.runId());
             QCOMPARE(facetArea, 1.0);
             #if qh_MAXoutside
                 double maxoutside= f.getFacetT()->maxoutside;
                 QVERIFY(maxoutside<1e-7);
             #endif
         }
     }
 }//t_value
 
 void QhullFacet_test::
 t_foreach()
 {
     RboxPoints rcube("c W0 300");  // cube plus 300 points on its surface
     {
         Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube
         int coplanarCount= 0;
         foreach(const QhullFacet f, q.facetList()){
             QhullPointSet coplanars= f.coplanarPoints();
             coplanarCount += coplanars.count();
             QhullFacetSet neighbors= f.neighborFacets();
             QCOMPARE(neighbors.count(), 4);
             QhullPointSet outsides= f.outsidePoints();
             QCOMPARE(outsides.count(), 0);
             QhullRidgeSet ridges= f.ridges();
             QCOMPARE(ridges.count(), 4);
             QhullVertexSet vertices= f.vertices();
             QCOMPARE(vertices.count(), 4);
             int ridgeCount= 0;
             QhullRidge r= ridges.first();
             for(int r0= r.id(); ridgeCount==0 || r.id()!=r0; r= r.nextRidge3d(f)){
                 ++ridgeCount;
                 if(!r.hasNextRidge3d(f)){
                     QFAIL("Unexpected simplicial facet.  They only have ridges to non-simplicial neighbors.");
                 }
             }
             QCOMPARE(ridgeCount, 4);
         }
         QCOMPARE(coplanarCount, 300);
     }
 }//t_foreach
 
 void QhullFacet_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullFacet f= q.beginFacet();
         cout << f;
         ostringstream os;
         os << f.printHeader(q.runId());
         os << f.printFlags("    - flags:");
         os << f.printCenter(q.runId(), qh_PRINTfacets, "    - center:");
         os << f.printRidges(q.runId());
         cout << os.str();
         ostringstream os2;
         os2 << f.print(q.runId());  // invokes print*()
         QString facetString2= QString::fromStdString(os2.str());
         facetString2.replace(QRegExp("\\s\\s+"), " ");
         ostringstream os3;
         q.setOutputStream(&os3);
         q.outputQhull("f");
         QString facetsString= QString::fromStdString(os3.str());
         QString facetString3= facetsString.mid(facetsString.indexOf("- f1\n"));
         facetString3= facetString3.left(facetString3.indexOf("\n- f")+1);
         facetString3.replace(QRegExp("\\s\\s+"), " ");
         QCOMPARE(facetString2, facetString3);
     }
 }//t_io
 
 // toQhullFacet is static_cast only
 
 }//orgQhull
 
 #include "moc/QhullFacet_test.moc"
diff --git a/src/qhullptest/QhullHyperplane_test.cpp b/src/qhullptest/QhullHyperplane_test.cpp
index 6053616..6d3d2a3 100644
--- a/src/qhullptest/QhullHyperplane_test.cpp
+++ b/src/qhullptest/QhullHyperplane_test.cpp
@@ -1,412 +1,412 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullHyperplane_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullHyperplane_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include 
 #include "RoadTest.h"
 
 #include "QhullHyperplane.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "Qhull.h"
 #include 
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullHyperplane_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_define();
     void t_value();
     void t_operator();
     void t_iterator();
     void t_const_iterator();
     void t_qhullHyperplane_iterator();
     void t_io();
 };//QhullHyperplane_test
 
 void
 add_QhullHyperplane_test()
 {
     new QhullHyperplane_test();
 }
 
 //Executed after each testcase
 void QhullHyperplane_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullHyperplane_test::
 t_construct()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullHyperplane h;
     QVERIFY(!h.isDefined());
     QCOMPARE(h.dimension(),0);
     QCOMPARE(h.coordinates(),static_cast(0));
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullHyperplane h2(f.hyperplane());
     QVERIFY(h2.isDefined());
     QCOMPARE(h2.dimension(),3);
     // h= h2;  // copy assignment disabled, ambiguous
     QhullHyperplane h3(h2.dimension(), h2.coordinates(), h2.offset());
     QCOMPARE(h2, h3);
     QhullHyperplane h5= h2; // copy constructor
     QVERIFY(h5==h2);
 }//t_construct
 
 void QhullHyperplane_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullHyperplane h= q.firstFacet().hyperplane();
     std::vector fs= h.toStdVector();
     QCOMPARE(fs.size(), 4u);
     double offset= fs.back();
     fs.pop_back();
     QCOMPARE(offset, -0.5);
 
     double squareNorm= inner_product(fs.begin(), fs.end(), fs.begin(), 0.0);
     QCOMPARE(squareNorm, 1.0);
     QList qs= h.toQList();
     QCOMPARE(qs.size(), 4);
     double offset2= qs.takeLast();
     QCOMPARE(offset2, -0.5);
     double squareNorm2= std::inner_product(qs.begin(), qs.end(), qs.begin(), 0.0);
     QCOMPARE(squareNorm2, 1.0);
 }//t_convert
 
 void QhullHyperplane_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullFacetList fs= q.facetList();
         QhullFacetListIterator i(fs);
         while(i.hasNext()){
             QhullFacet f= i.next();
             QhullHyperplane h= f.hyperplane();
             int id= f.id();
             cout << "h" << id << endl;
             QVERIFY(h.isDefined());
             QCOMPARE(h.dimension(),3);
             const coordT *c= h.coordinates();
             coordT *c2= h.coordinates();
             QCOMPARE(c, c2);
             const coordT *c3= h.begin();
             QCOMPARE(c, c3);
             QCOMPARE(h.offset(), -0.5);
             int j= h.end()-h.begin();
             QCOMPARE(j, 3);
             double squareNorm= std::inner_product(h.begin(), h.end(), h.begin(), 0.0);
             QCOMPARE(squareNorm, 1.0);
         }
         QhullHyperplane h2= fs.first().hyperplane();
         QhullHyperplane h3= fs.last().hyperplane();
         QVERIFY(h2!=h3);
         QVERIFY(h3.coordinates()!=h2.coordinates());
     }
 }//t_readonly
 
 void QhullHyperplane_test::
 t_define()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullFacetList fs= q.facetList();
         QhullHyperplane h= fs.first().hyperplane();
         QhullHyperplane h2= h;
         QVERIFY(h==h2);
         QhullHyperplane h3= fs.last().hyperplane();
         QVERIFY(h2!=h3);
 
         QhullHyperplane h4= h3;
         h4.defineAs(h2);
         QVERIFY(h2==h4);
         QhullHyperplane p5= h3;
         p5.defineAs(h2.dimension(), h2.coordinates(), h2.offset());
         QVERIFY(h2==p5);
         QhullHyperplane h6= h3;
         h6.setCoordinates(h2.coordinates());
         QCOMPARE(h2.coordinates(), h6.coordinates());
         h6.setOffset(h2.offset());
         QCOMPARE(h2.offset(), h6.offset());
         QVERIFY(h2==h6);
         h6.setDimension(2);
         QCOMPARE(h6.dimension(), 2);
         QVERIFY(h2!=h6);
     }
 }//t_define
 
 void QhullHyperplane_test::
 t_value()
 {
     RboxPoints rcube("c G1");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     const QhullHyperplane h= q.firstFacet().hyperplane();
     double dist= h.distance(q.origin());
     QCOMPARE(dist, -1.0);
     double norm= h.norm();
     QCOMPARE(norm, 1.0);
 }//t_value
 
 void QhullHyperplane_test::
 t_operator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     const QhullHyperplane h= q.firstFacet().hyperplane();
     //operator== and operator!= tested elsewhere
     const coordT *c= h.coordinates();
     for(int k=h.dimension(); k--; ){
         QCOMPARE(c[k], h[k]);
     }
     //h[0]= 10.0; // compiler error, const
     QhullHyperplane h2= q.firstFacet().hyperplane();
     h2[0]= 10.0;  // Overwrites Hyperplane coordinate!
     QCOMPARE(h2[0], 10.0);
 }//t_operator
 
 void QhullHyperplane_test::
 t_iterator()
 {
     RboxPoints rcube("c");
     {
         QhullHyperplane h2;
         QCOMPARE(h2.begin(), h2.end());
         QCOMPARE(h2.count(), 0);
         QCOMPARE(h2.size(), 0u);
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullHyperplane h= q.firstFacet().hyperplane();
         QCOMPARE(h.count(), 3);
         QCOMPARE(h.size(), 3u);
         QhullHyperplane::Iterator i= h.begin();
         QhullHyperplane::iterator i2= h.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= h.begin();
         QVERIFY(i==i2);
         i2= h.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, h[0]);
         QCOMPARE(d2, h[2]);
         QhullHyperplane::Iterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), h[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         QhullHyperplane::ConstIterator i4= h.begin();
         QVERIFY(i==i4); // iterator COMP const_iterator
         QVERIFY(i<=i4);
         QVERIFY(i>=i4);
         QVERIFY(i4==i); // const_iterator COMP iterator
         QVERIFY(i4<=i);
         QVERIFY(i4>=i);
         QVERIFY(i>=i4);
         QVERIFY(i4<=i);
         QVERIFY(i2!=i4);
         QVERIFY(i2>i4);
         QVERIFY(i2>=i4);
         QVERIFY(i4!=i2);
         QVERIFY(i4i);
         QVERIFY(i4>=i);
 
         i= h.begin();
         i2= h.begin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, h[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, h.begin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2 += 3, h.end());
         QCOMPARE(i2 -= 3, h.begin());
         QCOMPARE(i2+0, h.begin());
         QCOMPARE(i2+3, h.end());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, h.begin());
         QCOMPARE(i2-i, 3);
 
         //h.begin end tested above
 
         // QhullHyperplane is const-only
     }
 }//t_iterator
 
 void QhullHyperplane_test::
 t_const_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullHyperplane h= q.firstFacet().hyperplane();
         QhullHyperplane::ConstIterator i= h.begin();
         QhullHyperplane::const_iterator i2= h.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= h.begin();
         QVERIFY(i==i2);
         i2= h.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, h[0]);
         QCOMPARE(d2, h[2]);
         QhullHyperplane::ConstIterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), h[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         // See t_iterator for const_iterator COMP iterator
 
         i= h.begin();
         i2= h.constBegin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, h[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, h.constBegin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2+=3, h.constEnd());
         QCOMPARE(i2-=3, h.constBegin());
         QCOMPARE(i2+0, h.constBegin());
         QCOMPARE(i2+3, h.constEnd());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, h.constBegin());
         QCOMPARE(i2-i, 3);
 
         // QhullHyperplane is const-only
     }
 }//t_const_iterator
 
 void QhullHyperplane_test::
 t_qhullHyperplane_iterator()
 {
     QhullHyperplane h2;
     QhullHyperplaneIterator i= h2;
     QCOMPARE(h2.dimension(), 0);
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullHyperplane h = q.firstFacet().hyperplane();
     QhullHyperplaneIterator i2(h);
     QCOMPARE(h.dimension(), 3);
     i= h;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     // i at front, i2 at end/back, 3 coordinates
     QCOMPARE(i.peekNext(), h[0]);
     QCOMPARE(i2.peekPrevious(), h[2]);
     QCOMPARE(i2.previous(), h[2]);
     QCOMPARE(i2.previous(), h[1]);
     QCOMPARE(i2.previous(), h[0]);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), h[0]);
     // i.peekNext()= 1.0; // compiler error, i is const
     QCOMPARE(i.next(), h[0]);
     QCOMPARE(i.peekNext(), h[1]);
     QCOMPARE(i.next(), h[1]);
     QCOMPARE(i.next(), h[2]);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), h[0]);
 }//t_qhullHyperplane_iterator
 
 void QhullHyperplane_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullHyperplane h= q.firstFacet().hyperplane();
         ostringstream os;
         os << "Hyperplane:\n";
         os << h;
         os << "Hyperplane w/ runId:\n";
         os << h.print();
         os << h.print(" and a message ", " offset ");
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("1"), 3);
         // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
     }
 }//t_io
 
 
 }//orgQhull
 
 #include "moc/QhullHyperplane_test.moc"
diff --git a/src/qhullptest/QhullLinkedList_test.cpp b/src/qhullptest/QhullLinkedList_test.cpp
index ce93b88..b84c369 100644
--- a/src/qhullptest/QhullLinkedList_test.cpp
+++ b/src/qhullptest/QhullLinkedList_test.cpp
@@ -1,330 +1,330 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullLinkedList_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullLinkedList_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullLinkedList.h"
 #include "Qhull.h"
 
 namespace orgQhull {
 
 class QhullLinkedList_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_element();
     void t_search();
     void t_iterator();
     void t_const_iterator();
     void t_QhullLinkedList_iterator();
     void t_io();
 };//QhullLinkedList_test
 
 void
 add_QhullLinkedList_test()
 {
     new QhullLinkedList_test();
 }
 
 //Executed after each testcase
 void QhullLinkedList_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullLinkedList_test::
 t_construct()
 {
     // QhullLinkedList vs; //private (compiler error).  No memory allocation
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QhullVertexList vs = QhullVertexList(q.beginVertex(), q.endVertex());
         QCOMPARE(vs.count(), 8);
         QCOMPARE(vs.size(), 8u);
         QVERIFY(!vs.isEmpty());
         QhullVertexList vs2 = q.vertexList();
         QCOMPARE(vs2.count(), 8);
         QCOMPARE(vs2.size(),8u);
         QVERIFY(!vs2.isEmpty());
         QVERIFY(!vs2.empty());
         QVERIFY(vs==vs2);
         // vs= vs2; // disabled.  Would not copy the vertices
         QhullVertexList vs3= vs2; // copy constructor
         QVERIFY(vs3==vs2);
     }
 }//t_construct
 
 void QhullLinkedList_test::
 t_convert()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QhullVertexList vs = q.vertexList();
         QCOMPARE(vs.size(), 8u);
         QVERIFY(!vs.isEmpty());
         QVERIFY(!vs.empty());
         std::vector vs2= vs.toStdVector();
         QCOMPARE(vs2.size(), vs.size());
         QhullVertexList::Iterator i= vs.begin();
         for(int k= 0; k<(int)vs2.size(); k++){
             QCOMPARE(vs2[k], *i++);
         }
         QList vs3= vs.toQList();
         QCOMPARE(vs3.count(), vs.count());
         i= vs.begin();
         for(int k= 0; k
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullPointSet.h"
 #include "RboxPoints.h"
 #include "QhullPoint.h"
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 
 namespace orgQhull {
 
 class QhullPointSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_element();
     void t_iterator();
     void t_const_iterator();
     void t_search();
     void t_pointset_iterator();
     void t_io();
 };//QhullPointSet_test
 
 void
 add_QhullPointSet_test()
 {
     new QhullPointSet_test();
 }
 
 //Executed after each testcase
 void QhullPointSet_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullPointSet_test::
 t_construct()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     int coplanarCount= 0;
     foreach(QhullFacet f, q.facetList()){
         QhullPointSet ps(q.dimension(), f.getFacetT()->outsideset);
         QCOMPARE(ps.dimension(), 3);
         QVERIFY(ps.isEmpty());
         QVERIFY(ps.empty());
         QCOMPARE(ps.count(), 0);
         QCOMPARE(ps.size(), 0u);
         QhullPointSet ps2(q.dimension(), f.getFacetT()->coplanarset);
         QCOMPARE(ps2.dimension(), 3);
         QVERIFY(!ps2.isEmpty());
         QVERIFY(!ps2.empty());
         coplanarCount += ps2.count();
         QCOMPARE(ps2.count(), (int)ps2.size());
         QhullPointSet ps3(ps2);
         QCOMPARE(ps3.dimension(), 3);
         QVERIFY(!ps3.isEmpty());
         QCOMPARE(ps3.count(), ps2.count());
         QVERIFY(ps3==ps2);
         QVERIFY(ps3!=ps);
         // ps4= ps3; //compiler error
     }
     QCOMPARE(coplanarCount, 1000);
 }//t_construct
 
 void QhullPointSet_test::
 t_convert()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QCOMPARE(ps.dimension(), 3);
     QVERIFY(ps.count()>=1);   // Sometimes no coplanar points
     std::vector vs= ps.toStdVector();
     QCOMPARE(vs.size(), ps.size());
     QhullPoint p= ps[0];
     QhullPoint p2= vs[0];
     QCOMPARE(p, p2);
     QList qs= ps.toQList();
     QCOMPARE(qs.size(), static_cast(ps.size()));
     QhullPoint p3= qs[0];
     QCOMPARE(p3, p);
 }//t_convert
 
 // readonly tested in t_construct
 //   dimension, empty, isEmpty, ==, !=, size
 
 void QhullPointSet_test::
 t_element()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPoint p= ps[0];
     QCOMPARE(p, ps[0]);
     QhullPoint p2= ps[ps.count()-1];
     QCOMPARE(ps.at(1), ps[1]);
     QCOMPARE(ps.first(), p);
     QCOMPARE(ps.front(), ps.first());
     QCOMPARE(ps.last(), p2);
     QCOMPARE(ps.back(), ps.last());
     QhullPoint p8;
     QCOMPARE(ps.value(2), ps[2]);
     QCOMPARE(ps.value(-1), p8);
     QCOMPARE(ps.value(ps.count()), p8);
     QCOMPARE(ps.value(ps.count(), p), p);
     QVERIFY(ps.value(1, p)!=p);
     QhullPointSet ps8= f.coplanarPoints();
     QhullPointSet::Iterator i= ps8.begin();
     foreach(QhullPoint p9, ps){  // Qt only
         QCOMPARE(p9.dimension(), 3);
         QCOMPARE(p9, *i++);
     }
 }//t_element
 
 void QhullPointSet_test::
 t_iterator()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPointSet::Iterator i= ps.begin();
     QhullPointSet::iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p= *i;
     QCOMPARE(p.dimension(), ps.dimension());
     QCOMPARE(p, ps[0]);
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p2.dimension(), ps.dimension());
     QCOMPARE(p2, ps.last());
     QhullPointSet::Iterator i5(i2);
     QCOMPARE(*i2, *i5);
     QhullPointSet::Iterator i3= i+1;
     QVERIFY(i!=i3);
     QCOMPARE(i[1], *i3);
     (i3= i)++;
     QCOMPARE((*i3)[0], ps[1][0]);
     QCOMPARE((*i3).dimension(), 3);
 
     QVERIFY(i==i);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
 
     QhullPointSet::ConstIterator i4= ps.begin();
     QVERIFY(i==i4); // iterator COMP const_iterator
     QVERIFY(i<=i4);
     QVERIFY(i>=i4);
     QVERIFY(i4==i); // const_iterator COMP iterator
     QVERIFY(i4<=i);
     QVERIFY(i4>=i);
     QVERIFY(i>=i4);
     QVERIFY(i4<=i);
     QVERIFY(i2!=i4);
     QVERIFY(i2>i4);
     QVERIFY(i2>=i4);
     QVERIFY(i4!=i2);
     QVERIFY(i4i);
     QVERIFY(i4>=i);
 
     i= ps.begin();
     i2= ps.begin();
     QCOMPARE(i, i2++);
     QCOMPARE(*i2, ps[1]);
     QCOMPARE(++i, i2);
     QCOMPARE(i, i2--);
     QCOMPARE(i2, ps.begin());
     QCOMPARE(--i, i2);
     QCOMPARE(i2+=ps.count(), ps.end());
     QCOMPARE(i2-=ps.count(), ps.begin());
     QCOMPARE(i2+0, ps.begin());
     QCOMPARE(i2+ps.count(), ps.end());
     i2 += ps.count();
     i= i2-0;
     QCOMPARE(i, i2);
     i= i2-ps.count();
     QCOMPARE(i, ps.begin());
     QCOMPARE(i2-i, ps.count());
 
     //ps.begin end tested above
 
     // QhullPointSet is const-only
 }//t_iterator
 
 void QhullPointSet_test::
 t_const_iterator()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPointSet::ConstIterator i= ps.begin();
     QhullPointSet::const_iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
 
     // See t_iterator for const_iterator COMP iterator
 
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p= *i; // QhullPoint is the base class for QhullPointSet::iterator
     QCOMPARE(p.dimension(), ps.dimension());
     QCOMPARE(p, ps[0]);
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p2.dimension(), ps.dimension());
     QCOMPARE(p2, ps.last());
     QhullPointSet::ConstIterator i5(i2);
     QCOMPARE(*i2, *i5);
 
 
     QhullPointSet::ConstIterator i3= i+1;
     QVERIFY(i!=i3);
     QCOMPARE(i[1], *i3);
 
     QVERIFY(i==i);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
 
     // QhullPointSet is const-only
 }//t_const_iterator
 
 
 void QhullPointSet_test::
 t_search()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPoint p= ps.first();
     QhullPoint p2= ps.last();
     QVERIFY(ps.contains(p));
     QVERIFY(ps.contains(p2));
     QVERIFY(p!=p2);
     QhullPoint p3= ps[2];
     QVERIFY(ps.contains(p3));
     QVERIFY(p!=p3);
     QhullPoint p4;
     QCOMPARE(ps.indexOf(p), 0);
     QCOMPARE(ps.indexOf(p2), ps.count()-1);
     QCOMPARE(ps.indexOf(p3), 2);
     QCOMPARE(ps.indexOf(p4), -1);
     QCOMPARE(ps.lastIndexOf(p), 0);
     QCOMPARE(ps.lastIndexOf(p2), ps.count()-1);
     QCOMPARE(ps.lastIndexOf(p3), 2);
     QCOMPARE(ps.lastIndexOf(p4), -1);
 }//t_search
 
 void QhullPointSet_test::
 t_pointset_iterator()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps2= f.outsidePoints();
     QVERIFY(ps2.count()==0); // No outside points after constructing the convex hull
     QhullPointSetIterator i2= ps2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
 
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPointSetIterator i(ps);
     i2= ps;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullPoint p= ps[0];
     QhullPoint p2(ps[0]);
     QCOMPARE(p, p2);
     QVERIFY(p==p2);
     QhullPoint p3(ps.last());
  // p2[0]= 0.0;
     QVERIFY(p==p2);
     QCOMPARE(i2.peekPrevious(), p3);
     QCOMPARE(i2.previous(), p3);
     QCOMPARE(i2.previous(), ps[ps.count()-2]);
     QVERIFY(i2.hasPrevious());
     QCOMPARE(i.peekNext(), p);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), p);
     QhullPoint p4= i.peekNext();
     QVERIFY(p4!=p3);
     QCOMPARE(i.next(), p4);
     QVERIFY(i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p);
 }//t_pointset_iterator
 
 void QhullPointSet_test::
 t_io()
 {
     ostringstream os;
     RboxPoints rcube("c W0 120");
     Qhull q(rcube,"Qc");  // cube with 100 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     os << "QhullPointSet from coplanarPoints\n" << ps << endl;
     os << "\nRunId\n" << ps.print(q.runId());
     os << ps.print(q.runId(), "\nRunId w/ message\n");
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("p"), 3*ps.count()+1);
     // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullPointSet_test.moc"
diff --git a/src/qhullptest/QhullPoint_test.cpp b/src/qhullptest/QhullPoint_test.cpp
index 7afc070..d7aa94d 100644
--- a/src/qhullptest/QhullPoint_test.cpp
+++ b/src/qhullptest/QhullPoint_test.cpp
@@ -1,397 +1,397 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullPoint_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullPoint_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullPoint.h"
 #include "Coordinates.h"
 #include "RboxPoints.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "QhullPoint.h"
 #include "Qhull.h"
 
 #include 
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullPoint_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_define();
     void t_operator();
     void t_iterator();
     void t_const_iterator();
     void t_qhullpoint_iterator();
     void t_io();
 };//QhullPoint_test
 
 void
 add_QhullPoint_test()
 {
     new QhullPoint_test();
 }
 
 //Executed after each test
 void QhullPoint_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullPoint_test::
 t_construct()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullPoint p;
     QVERIFY(!p.isDefined());
     QCOMPARE(p.dimension(),0);
     QCOMPARE(p.coordinates(),static_cast(0));
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullVertex v2(q.beginVertex());
     QhullPoint p2(v2.point());
     QVERIFY(p2.isDefined());
     QCOMPARE(p2.dimension(),3);
     // p= p2;  // copy assignment disabled, ambiguous
     QhullPoint p3(p2.dimension(), p2.coordinates());
     QCOMPARE(p2, p3);
     Coordinates c;
     c << 0.0 << 0.0 << 0.0;
     QhullPoint p6(c);
     QCOMPARE(p6, q.origin());
     QhullPoint p5= p2; // copy constructor
     QVERIFY(p5==p2);
 }//t_construct
 
 void QhullPoint_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullVertex v= q.firstVertex();
     QhullPoint p= v.point();
     std::vector vs= p.toStdVector();
     QCOMPARE(vs.size(), 3u);
     for(int k=3; k--; ){
         QCOMPARE(vs[k], p[k]);
     }
     QList qs= p.toQList();
     QCOMPARE(qs.size(), 3);
     for(int k=3; k--; ){
         QCOMPARE(qs[k], p[k]);
     }
 }//t_convert
 
 void QhullPoint_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullVertexList vs= q.vertexList();
         QhullVertexListIterator i(vs);
         while(i.hasNext()){
             QhullPoint p= i.next().point();
             int id= p.id(q.runId());
             cout << "p" << id << endl;
             QVERIFY(p.isDefined());
             QCOMPARE(p.dimension(),3);
             QCOMPARE(id, p.id());
             QVERIFY(p.id()>=0 && p.id()<9);
             const coordT *c= p.coordinates();
             coordT *c2= p.coordinates();
             QCOMPARE(c, c2);
             QCOMPARE(p.dimension(), 3);
         }
         QhullPoint p2= vs.first().point();
         QhullPoint p3= vs.last().point();
         QVERIFY(p2!=p3);
         QVERIFY(p3.coordinates()!=p2.coordinates());
     }
 }//t_readonly
 
 void QhullPoint_test::
 t_define()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullVertexList vs= q.vertexList();
         QhullPoint p= vs.first().point();
         QhullPoint p2= p;
         QVERIFY(p==p2);
         QhullPoint p3= vs.last().point();
         QVERIFY(p2!=p3);
         int idx= (p3.coordinates()-p2.coordinates())/p2.dimension();
         QVERIFY(idx>-8 && idx<8);
         p2.advancePoint(idx);
         QVERIFY(p2==p3);
         p2.advancePoint(-idx);
         QVERIFY(p2==p);
         p2.advancePoint(0);
         QVERIFY(p2==p);
 
         QhullPoint p4= p3;
         p4.defineAs(p2);
         QVERIFY(p2==p4);
         QhullPoint p5= p3;
         p5.defineAs(p2.dimension(), p2.coordinates());
         QVERIFY(p2==p5);
         QhullPoint p6= p3;
         p6.setCoordinates(p2.coordinates());
         QCOMPARE(p2.coordinates(), p6.coordinates());
         QVERIFY(p2==p6);
         p6.setDimension(2);
         QCOMPARE(p6.dimension(), 2);
         QVERIFY(p2!=p6);
     }
 }//t_define
 
 void QhullPoint_test::
 t_operator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     const QhullPoint p= q.firstVertex().point();
     //operator== and operator!= tested elsewhere
     const coordT *c= p.coordinates();
     for(int k=p.dimension(); k--; ){
         QCOMPARE(c[k], p[k]);
     }
     //p[0]= 10.0; // compiler error, const
     QhullPoint p2= q.firstVertex().point();
     p2[0]= 10.0;  // Overwrites point coordinate
     QCOMPARE(p2[0], 10.0);
 }//t_operator
 
 void QhullPoint_test::
 t_iterator()
 {
     RboxPoints rcube("c");
     {
         QhullPoint p2;
         QCOMPARE(p2.begin(), p2.end());
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullPoint p= q.firstVertex().point();
         QhullPoint::Iterator i= p.begin();
         QhullPoint::iterator i2= p.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= p.begin();
         QVERIFY(i==i2);
         i2= p.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, p[0]);
         QCOMPARE(d2, p[2]);
         QhullPoint::Iterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), p[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         QhullPoint::ConstIterator i4= p.begin();
         QVERIFY(i==i4); // iterator COMP const_iterator
         QVERIFY(i<=i4);
         QVERIFY(i>=i4);
         QVERIFY(i4==i); // const_iterator COMP iterator
         QVERIFY(i4<=i);
         QVERIFY(i4>=i);
         QVERIFY(i>=i4);
         QVERIFY(i4<=i);
         QVERIFY(i2!=i4);
         QVERIFY(i2>i4);
         QVERIFY(i2>=i4);
         QVERIFY(i4!=i2);
         QVERIFY(i4i);
         QVERIFY(i4>=i);
 
         i= p.begin();
         i2= p.begin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, p[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, p.begin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2 += 3, p.end());
         QCOMPARE(i2 -= 3, p.begin());
         QCOMPARE(i2+0, p.begin());
         QCOMPARE(i2+3, p.end());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, p.begin());
         QCOMPARE(i2-i, 3);
 
         //p.begin end tested above
 
         // QhullPoint is const-only
     }
 }//t_iterator
 
 void QhullPoint_test::
 t_const_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullPoint p= q.firstVertex().point();
         QhullPoint::ConstIterator i= p.begin();
         QhullPoint::const_iterator i2= p.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= p.begin();
         QVERIFY(i==i2);
         i2= p.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, p[0]);
         QCOMPARE(d2, p[2]);
         QhullPoint::ConstIterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), p[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         // See t_iterator for const_iterator COMP iterator
 
         i= p.begin();
         i2= p.constBegin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, p[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, p.constBegin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2+=3, p.constEnd());
         QCOMPARE(i2-=3, p.constBegin());
         QCOMPARE(i2+0, p.constBegin());
         QCOMPARE(i2+3, p.constEnd());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, p.constBegin());
         QCOMPARE(i2-i, 3);
 
         // QhullPoint is const-only
     }
 }//t_const_iterator
 
 void QhullPoint_test::
 t_qhullpoint_iterator()
 {
     QhullPoint p2;
     QhullPointIterator i= p2;
     QCOMPARE(p2.dimension(), 0);
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullPoint p = q.firstVertex().point();
     QhullPointIterator i2(p);
     QCOMPARE(p.dimension(), 3);
     i= p;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     // i at front, i2 at end/back, 3 coordinates
     QCOMPARE(i.peekNext(), p[0]);
     QCOMPARE(i2.peekPrevious(), p[2]);
     QCOMPARE(i2.previous(), p[2]);
     QCOMPARE(i2.previous(), p[1]);
     QCOMPARE(i2.previous(), p[0]);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), p[0]);
     // i.peekNext()= 1.0; // compiler error, i is const
     QCOMPARE(i.next(), p[0]);
     QCOMPARE(i.peekNext(), p[1]);
     QCOMPARE(i.next(), p[1]);
     QCOMPARE(i.next(), p[2]);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p[0]);
 }//t_qhullpoint_iterator
 
 void QhullPoint_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullPoint p= q.beginVertex().point();
         ostringstream os;
         os << "Point w/o runId:\n";
         os << p;
         os << "Point w/ runId:\n";
         os << p.print(q.runId()) << p.print(q.runId(), " and a message ");
         os << p.printWithIdentifier(q.runId(), " Point with id and a message ");
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("p"), 3);
         // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullPoint_test.moc"
diff --git a/src/qhullptest/QhullPoints_test.cpp b/src/qhullptest/QhullPoints_test.cpp
index ba12ff5..4591c06 100644
--- a/src/qhullptest/QhullPoints_test.cpp
+++ b/src/qhullptest/QhullPoints_test.cpp
@@ -1,481 +1,481 @@
 /****************************************************************************
 **
-** Copyright (p) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullPoints_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (p) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullPoints_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled header
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullPoints.h"
 #include "RboxPoints.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 
 namespace orgQhull {
 
 class QhullPoints_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_getset();
     void t_element();
     void t_iterator();
     void t_const_iterator();
     void t_search();
     void t_points_iterator();
     void t_io();
 };//QhullPoints_test
 
 void
 add_QhullPoints_test()
 {
     new QhullPoints_test();
 }
 
 //Executed after each testcase
 void QhullPoints_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullPoints_test::
 t_construct()
 {
     QhullPoints ps;
     QCOMPARE(ps.dimension(), 0);
     QVERIFY(ps.isEmpty());
     QVERIFY(ps.empty());
     QCOMPARE(ps.count(), 0);
     QCOMPARE(ps.size(), 0u);
     QCOMPARE(ps.coordinateCount(), 0);
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps2;
     ps2.defineAs(2, 6, c);
     QCOMPARE(ps2.dimension(), 2);
     QVERIFY(!ps2.isEmpty());
     QVERIFY(!ps2.empty());
     QCOMPARE(ps2.count(), 3);
     QCOMPARE(ps2.size(), 3u);
     QCOMPARE(ps2.coordinates(), c);
     QhullPoints ps7(3);
     QCOMPARE(ps7.dimension(), 3);
     QVERIFY(ps7.isEmpty());
     QhullPoints ps3(2, 6, c);
     QCOMPARE(ps3.dimension(), 2);
     QVERIFY(!ps3.isEmpty());
     QCOMPARE(ps3.coordinates(), ps2.coordinates());
     QVERIFY(ps3==ps2);
     QVERIFY(ps3!=ps);
     QhullPoints ps4= ps3;
     QVERIFY(ps4==ps3);
     // ps4= ps3; //compiler error
     QhullPoints ps5(ps4);
     QVERIFY(ps5==ps4);
     QVERIFY(!(ps5!=ps4));
     coordT c2[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps6(2, 6, c2);
     QVERIFY(ps6==ps2);
 }//t_construct
 
 void QhullPoints_test::
 t_convert()
 {
     //defineAs tested above
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(3, 6, c);
     QCOMPARE(ps.dimension(), 3);
     QCOMPARE(ps.size(), 2u);
     const coordT *c2= ps.constData();
     QCOMPARE(c, c2);
     const coordT *c3= ps.data();
     QCOMPARE(c, c3);
     coordT *c4= ps.data();
     QCOMPARE(c, c4);
     std::vector vs= ps.toStdVector();
     QCOMPARE(vs.size(), 2u);
     QhullPoint p= vs[1];
     QCOMPARE(p[2], 5.0);
     QList qs= ps.toQList();
     QCOMPARE(qs.size(), 2);
     QhullPoint p2= qs[1];
     QCOMPARE(p2[2], 5.0);
 }//t_convert
 
 void QhullPoints_test::
 t_getset()
 {
     //See t_construct for coordinates, count, defineAs, dimension, empty, isempty, ==, !=, size
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(3, 6, c);
     QhullPoints ps2(3, 6, c);
     QCOMPARE(ps2.dimension(), 3);
     QCOMPARE(ps2.coordinates(), c);
     QCOMPARE(ps2.count(), 2);
     QCOMPARE(ps2.coordinateCount(), 6);
     coordT c2[]= {-1.0, -2.0, -3.0, -4.0, -5.0, -6.0};
     ps2.defineAs(6, c2);
     QCOMPARE(ps2.coordinates(), c2);
     QCOMPARE(ps2.count(), 2);
     QCOMPARE(ps2.size(), 2u);
     QCOMPARE(ps2.dimension(), 3);
     QVERIFY(!ps2.isEmpty());
     QVERIFY(ps!=ps2);
     // ps2= ps; // assignment not available, compiler error
     ps2.defineAs(ps);
     QVERIFY(ps==ps2);
     ps2.setDimension(2);
     QCOMPARE(ps2.dimension(), 2);
     QCOMPARE(ps2.coordinates(), c);
     QVERIFY(!ps2.isEmpty());
     QCOMPARE(ps2.count(), 3);
     QCOMPARE(ps2.size(), 3u);
     QVERIFY(ps!=ps2);
     QhullPoints ps3(3);
     ps3.defineAs(5, c2);
     QCOMPARE(ps3.count(), 1);
     QCOMPARE(ps3.extraCoordinatesCount(), 2);
     QCOMPARE(ps3.extraCoordinates()[0], -4.0);
     QVERIFY(ps3.includesCoordinates(ps3.data()));
     QVERIFY(ps3.includesCoordinates(ps3.data()+ps3.count()-1));
     QVERIFY(!ps3.includesCoordinates(ps3.data()-1));
     QVERIFY(!ps3.includesCoordinates(ps3.data()+ps3.coordinateCount()));
 }//t_getset
 
 
 void QhullPoints_test::
 t_element()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(2, 6, c);
     QhullPoint p(2, c);
     QCOMPARE(ps[0], p);
     QCOMPARE(ps.at(1), ps[1]);
     QCOMPARE(ps.first(), p);
     QCOMPARE(ps.front(), ps.first());
     QCOMPARE(ps.last(), ps.at(2));
     QCOMPARE(ps.back(), ps.last());
     QhullPoints ps2= ps.mid(2);
     QCOMPARE(ps2.count(), 1);
     QhullPoints ps3= ps.mid(3);
     QVERIFY(ps3.isEmpty());
     QVERIFY(ps3.empty());
     QhullPoints ps4= ps.mid(10);
     QVERIFY(ps4.isEmpty());
     QhullPoints ps5= ps.mid(-1);
     QVERIFY(ps5.isEmpty());
     QhullPoints ps6= ps.mid(1, 1);
     QCOMPARE(ps6.count(), 1);
     QCOMPARE(ps6[0], ps[1]);
     QhullPoints ps7= ps.mid(1, 10);
     QCOMPARE(ps7.count(), 2);
     QCOMPARE(ps7[1], ps[2]);
     QhullPoint p8;
     QCOMPARE(ps.value(2), ps[2]);
     QCOMPARE(ps.value(-1), p8);
     QCOMPARE(ps.value(3), p8);
     QCOMPARE(ps.value(3, p), p);
     QVERIFY(ps.value(1, p)!=p);
     foreach(QhullPoint p9, ps){  // Qt only
         QCOMPARE(p9.dimension(), 2);
         QVERIFY(p9[0]==0.0 || p9[0]==2.0 || p9[0]==4.0);
     }
 }//t_element
 
 void QhullPoints_test::
 t_iterator()
 {
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoints ps(1, 3, c);
     QhullPoints::Iterator i(ps);
     QhullPoints::iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p(i); // QhullPoint is the base class for QhullPoints::iterator
     QCOMPARE(p.dimension(), ps.dimension());
     QCOMPARE(p.coordinates(), ps.coordinates());
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p[0], 0.0);
     QCOMPARE(p2[0], 2.0);
     QhullPoints::Iterator i5(i2);
     QCOMPARE(*i2, *i5);
     coordT c3[]= {0.0, -1.0, -2.0};
     QhullPoints::Iterator i3(1, c3);
     QVERIFY(i!=i3);
     QCOMPARE(*i, *i3);
 
     (i3= i)++;
     QCOMPARE((*i3)[0], 1.0);
     QCOMPARE(i3->dimension(), 1);
     QCOMPARE(i3[0][0], 1.0);
     QCOMPARE(i3[0], ps[1]);
 
     QVERIFY(i==i);
     QVERIFY(i!=i2);
     QVERIFY(ii);
     QVERIFY(i2>=i);
 
     QhullPoints::ConstIterator i4(1, c);
     QVERIFY(i==i4); // iterator COMP const_iterator
     QVERIFY(i<=i4);
     QVERIFY(i>=i4);
     QVERIFY(i4==i); // const_iterator COMP iterator
     QVERIFY(i4<=i);
     QVERIFY(i4>=i);
     QVERIFY(i>=i4);
     QVERIFY(i4<=i);
     QVERIFY(i2!=i4);
     QVERIFY(i2>i4);
     QVERIFY(i2>=i4);
     QVERIFY(i4!=i2);
     QVERIFY(i4i);
     QVERIFY(i4>=i);
 
     i= ps.begin();
     i2= ps.begin();
     QCOMPARE(i, i2++);
     QCOMPARE(*i2, ps[1]);
     QCOMPARE(++i, i2);
     QCOMPARE(i, i2--);
     QCOMPARE(i2, ps.begin());
     QCOMPARE(--i, i2);
     QCOMPARE(i2+=3, ps.end());
     QCOMPARE(i2-=3, ps.begin());
     QCOMPARE(i2+0, ps.begin());
     QCOMPARE(i2+3, ps.end());
     i2 += 3;
     i= i2-0;
     QCOMPARE(i, i2);
     i= i2-3;
     QCOMPARE(i, ps.begin());
     QCOMPARE(i2-i, 3);
 
     //ps.begin end tested above
 
     // QhullPoints is const-only
 }//t_iterator
 
 void QhullPoints_test::
 t_const_iterator()
 {
     coordT c[]= {0.0, 1.0, 2.0};
     const QhullPoints ps(1, 3, c);
     QhullPoints::ConstIterator i(ps);
     QhullPoints::const_iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p(i);
     QCOMPARE(p.dimension(), ps.dimension());
     QCOMPARE(p.coordinates(), ps.coordinates());
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p[0], 0.0);
     QCOMPARE(p2[0], 2.0);
     QhullPoints::ConstIterator i5(i2);
     QCOMPARE(*i2, *i5);
     coordT c3[]= {0.0, -1.0, -2.0};
     QhullPoints::ConstIterator i3(1, c3);
     QVERIFY(i!=i3);
     QCOMPARE(*i, *i3);
 
     (i3= i)++;
     QCOMPARE((*i3)[0], 1.0);
     QCOMPARE(i3->dimension(), 1);
     QCOMPARE(i3[0][0], 1.0);
     QCOMPARE(i3[0][0], 1.0);
     QCOMPARE(i3[0], ps[1]);
 
     QVERIFY(i==i);
     QVERIFY(i!=i2);
     QVERIFY(ii);
     QVERIFY(i2>=i);
 
     // See t_iterator for const_iterator COMP iterator
 
     i= ps.begin();
     i2= ps.constBegin();
     QCOMPARE(i, i2++);
     QCOMPARE(*i2, ps[1]);
     QCOMPARE(++i, i2);
     QCOMPARE(i, i2--);
     QCOMPARE(i2, ps.constBegin());
     QCOMPARE(--i, i2);
     QCOMPARE(i2+=3, ps.constEnd());
     QCOMPARE(i2-=3, ps.constBegin());
     QCOMPARE(i2+0, ps.constBegin());
     QCOMPARE(i2+3, ps.constEnd());
     i2 += 3;
     i= i2-0;
     QCOMPARE(i, i2);
     i= i2-3;
     QCOMPARE(i, ps.constBegin());
     QCOMPARE(i2-i, 3);
 
     // QhullPoints is const-only
 }//t_const_iterator
 
 
 void QhullPoints_test::
 t_search()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0, 1};
     QhullPoints ps(2, 8, c); //2-d array of 4 points
     QhullPoint p= ps.first();
     QhullPoint p2= ps.last();
     QVERIFY(ps.contains(p));
     QVERIFY(ps.contains(p2));
     QVERIFY(p==p2);
     QhullPoint p5= ps[2];
     QVERIFY(p!=p5);
     QVERIFY(ps.contains(p5));
     coordT c2[]= {0.0, 1.0, 2.0, 3.0};
     QhullPoint p3(2, c2); //2-d point
     QVERIFY(ps.contains(p3));
     QhullPoint p4(3, c2); //3-d point
     QVERIFY(!ps.contains(p4));
     p4.defineAs(2, c); //2-d point
     QVERIFY(ps.contains(p4));
     p4.defineAs(2, c+1); //2-d point
     QVERIFY(!ps.contains(p4));
     QhullPoint p6(2, c2+2); //2-d point
     QCOMPARE(ps.count(p), 2);
     QCOMPARE(ps.count(p2), 2);
     QCOMPARE(ps.count(p3), 2);
     QCOMPARE(ps.count(p4), 0);
     QCOMPARE(ps.count(p6), 1);
     QCOMPARE(ps.indexOf(&ps[0][0]), 0);
     //QCOMPARE(ps.indexOf(ps.end()), -1); //ps.end() is a QhullPoint which may match
     QCOMPARE(ps.indexOf(0), -1);
     QCOMPARE(ps.indexOf(&ps[3][0]), 3);
     QCOMPARE(ps.indexOf(&ps[3][1], QhullError::NOthrow), 3);
     QCOMPARE(ps.indexOf(ps.data()+ps.coordinateCount(), QhullError::NOthrow), -1);
     QCOMPARE(ps.indexOf(p), 0);
     QCOMPARE(ps.indexOf(p2), 0);
     QCOMPARE(ps.indexOf(p3), 0);
     QCOMPARE(ps.indexOf(p4), -1);
     QCOMPARE(ps.indexOf(p5), 2);
     QCOMPARE(ps.indexOf(p6), 1);
     QCOMPARE(ps.lastIndexOf(p), 3);
     QCOMPARE(ps.lastIndexOf(p4), -1);
     QCOMPARE(ps.lastIndexOf(p6), 1);
     QhullPoints ps2(3);
     QCOMPARE(ps2.indexOf(ps2.data()), -1);
     QCOMPARE(ps2.indexOf(ps2.data()+1, QhullError::NOthrow), -1);
     QCOMPARE(ps2.indexOf(p), -1);
     QCOMPARE(ps2.lastIndexOf(p), -1);
     QhullPoints ps3;
     QCOMPARE(ps3.indexOf(ps3.data()), -1);
     QCOMPARE(ps3.indexOf(ps3.data()+1, QhullError::NOthrow), -1);
     QCOMPARE(ps3.indexOf(p), -1);
     QCOMPARE(ps3.lastIndexOf(p), -1);
     QhullPoints ps4(2, 0, c);
     QCOMPARE(ps4.indexOf(p), -1);
     QCOMPARE(ps4.lastIndexOf(p), -1);
 }//t_search
 
 void QhullPoints_test::
 t_points_iterator()
 {
     coordT c2[]= {0.0};
     QhullPoints ps2(0, 0, c2); // 0-dimensional
     QhullPointsIterator i2= ps2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
 
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(3, 6, c); // 3-dimensional
     QhullPointsIterator i(ps);
     i2= ps;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullPoint p= ps[0];
     QhullPoint p2(ps[0]);
     QCOMPARE(p, p2);
     QVERIFY(p==p2);
     QhullPoint p3(ps[1]);
  // p2[0]= 0.0;
     QVERIFY(p==p2);
     QCOMPARE(i2.peekPrevious(), p3);
     QCOMPARE(i2.previous(), p3);
     QCOMPARE(i2.previous(), p);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), p);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), p);
     QCOMPARE(i.peekNext(), p3);
     QCOMPARE(i.next(), p3);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p);
 }//t_points_iterator
 
 void QhullPoints_test::
 t_io()
 {
     QhullPoints ps;
     ostringstream os;
     os << "Empty QhullPoints\n" << ps << endl;
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps2(3, 6, c); // 3-dimensional explicit
     os << "QhullPoints from c[]\n" << ps2 << endl;
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullPoints ps3= q.points();
     os << "QhullPoints\n" << ps3;
     os << "RunId\n" << ps3.print(q.runId());
     os << ps3.print(q.runId(), "RunId w/ message\n");
     os << ps3.printWithIdentifier(q.runId(), "RunId w/ identifiers\n");
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("p"), 3*8+3);
     // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullPoints_test.moc"
diff --git a/src/qhullptest/QhullRidge_test.cpp b/src/qhullptest/QhullRidge_test.cpp
index 6407b8f..1fbccd1 100644
--- a/src/qhullptest/QhullRidge_test.cpp
+++ b/src/qhullptest/QhullRidge_test.cpp
@@ -1,163 +1,163 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullRidge_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullRidge_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullRidge.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullRidge_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_getSet();
     void t_foreach();
     void t_io();
 };//QhullRidge_test
 
 void
 add_QhullRidge_test()
 {
     new QhullRidge_test();
 }
 
 //Executed after each testcase
 void QhullRidge_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullRidge_test::
 t_construct()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullRidge r;
     QVERIFY(!r.isDefined());
     QCOMPARE(r.dimension(),0);
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
     QhullFacet f(q.firstFacet());
     QhullRidgeSet rs(f.ridges());
     QVERIFY(!rs.isEmpty()); // Simplicial facets do not have ridges()
     QhullRidge r2(rs.first());
     QCOMPARE(r2.dimension(), 2); // One dimension lower than the facet
     r= r2;
     QVERIFY(r.isDefined());
     QCOMPARE(r.dimension(), 2);
     QhullRidge r3= r2.getRidgeT();
     QCOMPARE(r,r3);
     QhullRidge r4= r2.getBaseT();
     QCOMPARE(r,r4);
     QhullRidge r5= r2; // copy constructor
     QVERIFY(r5==r2);
     QVERIFY(r5==r);
 }//t_construct
 
 void QhullRidge_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 6);
         QCOMPARE(q.vertexCount(), 8);
         QhullFacet f(q.firstFacet());
         QhullRidgeSet rs= f.ridges();
         QhullRidgeSetIterator i(rs);
         while(i.hasNext()){
             const QhullRidge r= i.next();
             cout << r.id() << endl;
             QVERIFY(r.bottomFacet()!=r.topFacet());
             QCOMPARE(r.dimension(), 2); // Ridge one-dimension less than facet
             QVERIFY(r.id()>=0 && r.id()<9*27);
             QVERIFY(r.isDefined());
             QVERIFY(r==r);
             QVERIFY(r==i.peekPrevious());
             QCOMPARE(r.otherFacet(r.bottomFacet()),r.topFacet());
             QCOMPARE(r.otherFacet(r.topFacet()),r.bottomFacet());
         }
         QhullRidgeSetIterator i2(i);
         QEXPECT_FAIL("", "SetIterator copy constructor not reset to BOT", Continue);
         QVERIFY(!i2.hasPrevious());
     }
 }//t_getSet
 
 void QhullRidge_test::
 t_foreach()
 {
     RboxPoints rcube("c");  // cube
     {
         Qhull q(rcube, "QR0"); // rotated cube
         QhullFacet f(q.firstFacet());
         foreach (QhullRidge r, f.ridges()){  // Qt only
             QhullVertexSet vs= r.vertices();
             QCOMPARE(vs.count(), 2);
             foreach (QhullVertex v, vs){  // Qt only
                 QVERIFY(f.vertices().contains(v));
             }
         }
         QhullRidgeSet rs= f.ridges();
         QhullRidge r= rs.first();
         QhullRidge r2= r;
         QList vs;
         int count= 0;
         while(!count || r2!=r){
             ++count;
             QhullVertex v;
             QVERIFY2(r2.hasNextRidge3d(f),"A cube should only have non-simplicial facets.");
             QhullRidge r3= r2.nextRidge3d(f, &v);
             QVERIFY(!vs.contains(v));
             vs << v;
             r2= r2.nextRidge3d(f);
             QCOMPARE(r3, r2);
         }
         QCOMPARE(vs.count(), rs.count());
         QCOMPARE(count, rs.count());
     }
 }//t_foreach
 
 void QhullRidge_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullFacet f(q.firstFacet());
         QhullRidgeSet rs= f.ridges();
         QhullRidge r= rs.first();
         ostringstream os;
         os << "Ridges Without runId\n" << rs << "Ridge\n" << r;
         os << "Ridge with runId\n" << r.print(q.runId());
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count(" r"), 6+2);
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullRidge_test.moc"
diff --git a/src/qhullptest/QhullSet_test.cpp b/src/qhullptest/QhullSet_test.cpp
index 04460a8..9f8e57a 100644
--- a/src/qhullptest/QhullSet_test.cpp
+++ b/src/qhullptest/QhullSet_test.cpp
@@ -1,435 +1,435 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullSet_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullSet_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullRidge.h"
 #include "QhullFacetSet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 
 namespace orgQhull {
 
 class QhullSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_qhullsetbase();
     void t_convert();
     void t_element();
     void t_search();
     void t_iterator();
     void t_const_iterator();
     void t_qhullset_iterator();
     void t_io();
 };//QhullSet_test
 
 void
 add_QhullSet_test()
 {
     new QhullSet_test();
 }
 
 //Executed after each testcase
 void QhullSet_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 // Test QhullFacetSet and QhullSet.
 // Use QhullRidgeSet to test methods overloaded by QhullFacetSet
 
 void QhullSet_test::
 t_qhullsetbase()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
         // Fake an empty set.  Default constructor not defined.  No memory allocation.
         QhullFacet f4 = q.beginFacet();
         QhullFacetSet fs = f4.neighborFacets();
         fs.defineAs(q.qhullQh()->other_points); // Force an empty set
         QVERIFY(fs.isEmpty());
         QVERIFY(fs.empty());
         QCOMPARE(fs.count(), 0);
         QCOMPARE(fs.size(), 0u);
         QCOMPARE(fs.begin(), fs.end()); // beginPointer(), endPointer()
         QVERIFY(QhullSetBase::isEmpty(fs.getSetT()));
 
         QhullRidgeSet rs = f4.ridges();
         QVERIFY(!rs.isEmpty());
         QVERIFY(!rs.empty());
         QCOMPARE(rs.count(), 4);
         QCOMPARE(rs.size(), 4u);
         QVERIFY(rs.begin()!=rs.end());
         QVERIFY(!QhullSetBase::isEmpty(rs.getSetT()));
         QhullRidgeSet rs2= rs; // copy constructor
         // rs= rs2; // disabled.  Would not copy ridges
         QCOMPARE(rs2, rs);
 
         QCOMPARE(q.facetCount(), 6);
         QhullFacet f = q.beginFacet();
         QhullFacetSet fs2 = f.neighborFacets();
         QCOMPARE(fs2.count(), 4);
         QCOMPARE(fs2.size(), 4u);
         QVERIFY(!fs2.isEmpty());
         QVERIFY(!QhullSetBase::isEmpty(fs2.getSetT()));
         QVERIFY(!fs2.empty());
         QVERIFY(fs!=fs2);
         setT *s= fs2.getSetT();
         fs.defineAs(s);
         QVERIFY(fs==fs2);
         QCOMPARE(fs[1], fs2[1]); // elementPointer
         QhullFacetSet fs3(fs2);
         QVERIFY(fs3==fs);
         // fs= fs2; // disabled.  Would not copy facets
         QhullFacetSet fs4= fs2; // copy constructor
         QVERIFY(fs4==fs2);
     }
 }//t_qhullsetbase
 
 // constructors tested by t_qhullsetbase
 
 void QhullSet_test::
 t_convert()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullFacet f= q.firstFacet();
         f= f.next();
         QhullRidgeSet rs= f.ridges();
         QCOMPARE(rs.count(),4);
         std::vector rv= rs.toStdVector();
         QCOMPARE(rv.size(), 4u);
         QList rv2= rs.toQList();
         QCOMPARE(rv2.size(), 4);
         std::vector::iterator i= rv.begin();
         foreach(QhullRidge r, rv2){  // Qt only
             QhullRidge r2= *i++;
             QCOMPARE(r, r2);
         }
 
         Qhull q2(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q2.facetCount(), 12);
         QhullFacet f2 = q2.beginFacet();
         QhullFacetSet fs = f2.neighborFacets();
         QCOMPARE(fs.size(), 3U);
         std::vector vs= fs.toStdVector();
         QCOMPARE(vs.size(), fs.size());
         for(int k= fs.count(); k--; ){
             QCOMPARE(vs[k], fs[k]);
         }
         QList qv= fs.toQList();
         QCOMPARE(qv.count(), fs.count());
         for(int k= fs.count(); k--; ){
             QCOMPARE(qv[k], fs[k]);
         }
     }
 }//t_convert
 
 //ReadOnly (count, isEmpty) tested by t_convert
 //  operator== tested by t_search
 
 void QhullSet_test::
 t_element()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f = q.beginFacet();
     QhullFacetSet fs = f.neighborFacets();
 
     QCOMPARE(fs.at(1), fs[1]);
     QCOMPARE(fs.first(), fs[0]);
     QCOMPARE(fs.front(), fs.first());
     QCOMPARE(fs.last(), fs.at(3));
     QCOMPARE(fs.back(), fs.last());
     QhullFacet *d= fs.data();
     const QhullFacet *d2= fs.data();
     const QhullFacet *d3= fs.constData();
     QVERIFY(d==d2);
     QVERIFY(d2==d3);
     QCOMPARE(*d, fs.first());
     QCOMPARE(d+4, fs.end());
     QCOMPARE((d+4)->getFacetT(), static_cast(0));
     QhullFacet f4= *(d+4);
     QVERIFY(!f4.isDefined());
     QCOMPARE(fs.second(), fs[1]);
     const QhullFacet f2= fs.second();
     QVERIFY(f2==fs[1]);
     const QhullFacet f3= fs[1];
     QCOMPARE(f2, f3);
 
     QCOMPARE(fs.value(2), fs[2]);
     QCOMPARE(fs.value(-1), QhullFacet());
     QCOMPARE(fs.value(10), QhullFacet());
     QCOMPARE(fs.value(2, f), fs[2]);
     QCOMPARE(fs.value(4, f), f);
     // mid() not available (read-only)
 }//t_element
 
 void QhullSet_test::
 t_search()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f = q.beginFacet();
     QhullFacetSet fs = f.neighborFacets();
     QhullFacet f2= *fs.begin();
     QhullFacet f3= fs.last();
     QVERIFY(fs.contains(f2));
     QVERIFY(fs.contains(f3));
     QVERIFY(!fs.contains(f));
 
     QhullFacetSet fs2= f2.neighborFacets();
     QVERIFY(fs==fs);
     QVERIFY(fs!=fs2);
     QCOMPARE(fs.count(f2), 1);
     QCOMPARE(fs.count(f3), 1);
     QCOMPARE(fs.count(f), 0);
     QCOMPARE(fs.indexOf(f2), 0);
     QCOMPARE(fs.indexOf(f3), 3);
     QCOMPARE(fs.indexOf(f), -1);
     QCOMPARE(fs.lastIndexOf(f2), 0);
     QCOMPARE(fs.lastIndexOf(f3), 3);
     QCOMPARE(fs.lastIndexOf(f), -1);
 }//t_search
 
 void QhullSet_test::
 t_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullFacet f = q.beginFacet();
         QhullFacetSet fs = f.neighborFacets();
         QhullFacetSet::Iterator i= fs.begin();
         QhullFacetSet::iterator i2= fs.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= fs.begin();
         QVERIFY(i==i2);
         i2= fs.end();
         QVERIFY(i!=i2);
         QhullFacet f3(*i);
         i2--;
         QhullFacet f2= *i2;
         QCOMPARE(f3.id(), fs[0].id());
         QCOMPARE(f2.id(), fs[3].id());
         QhullFacetSet::Iterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3).id(), fs[1].id());
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         QhullFacetSet::ConstIterator i4= fs.begin();
         QVERIFY(i==i4); // iterator COMP const_iterator
         QVERIFY(i<=i4);
         QVERIFY(i>=i4);
         QVERIFY(i4==i); // const_iterator COMP iterator
         QVERIFY(i4<=i);
         QVERIFY(i4>=i);
         QVERIFY(i>=i4);
         QVERIFY(i4<=i);
         QVERIFY(i2!=i4);
         QVERIFY(i2>i4);
         QVERIFY(i2>=i4);
         QVERIFY(i4!=i2);
         QVERIFY(i4i);
         QVERIFY(i4>=i);
 
         i= fs.begin();
         i2= fs.begin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, fs[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, fs.begin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2 += 4, fs.end());
         QCOMPARE(i2 -= 4, fs.begin());
         QCOMPARE(i2+0, fs.begin());
         QCOMPARE(i2+4, fs.end());
         i2 += 4;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-4;
         QCOMPARE(i, fs.begin());
         QCOMPARE(i2-i, 4);
 
         //fs.begin end tested above
 
         // QhullFacetSet is const-only
     }
 }//t_iterator
 
 void QhullSet_test::
 t_const_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullFacet f = q.beginFacet();
         QhullFacetSet fs = f.neighborFacets();
         QhullFacetSet::ConstIterator i= fs.begin();
         QhullFacetSet::const_iterator i2= fs.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= fs.begin();
         QVERIFY(i==i2);
         i2= fs.end();
         QVERIFY(i!=i2);
         QhullFacet f3(*i);
         i2--;
         QhullFacet f2= *i2;
         QCOMPARE(f3.id(), fs[0].id());
         QCOMPARE(f2.id(), fs[3].id());
         QhullFacetSet::ConstIterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3).id(), fs[1].id());
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         // See t_iterator for const_iterator COMP iterator
 
         i= fs.begin();
         i2= fs.constBegin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, fs[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, fs.constBegin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2+=4, fs.constEnd());
         QCOMPARE(i2-=4, fs.constBegin());
         QCOMPARE(i2+0, fs.constBegin());
         QCOMPARE(i2+4, fs.constEnd());
         i2 += 4;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-4;
         QCOMPARE(i, fs.constBegin());
         QCOMPARE(i2-i, 4);
 
         // QhullFacetSet is const-only
     }
 }//t_const_iterator
 
 void QhullSet_test::
 t_qhullset_iterator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     // Fake an empty set.  Default constructor not defined.  No memory allocation.
     QhullFacet f = q.beginFacet();
     QhullFacetSet fs = f.neighborFacets();
     fs.defineAs(q.qhullQh()->other_points);
     QhullFacetSetIterator i= fs;
     QCOMPARE(fs.count(), 0);
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullFacet f2 = q.beginFacet();
     QhullFacetSet fs2 = f2.neighborFacets();
     QhullFacetSetIterator i2(fs2);
     QCOMPARE(fs2.count(), 4);
     i= fs2;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     // i at front, i2 at end/back, 4 neighbors
     QhullFacetSet fs3 = f2.neighborFacets(); // same as fs2
     QhullFacet f3(fs2[0]);
     QhullFacet f4= fs3[0];
     QCOMPARE(f3, f4);
     QVERIFY(f3==f4);
     QhullFacet f5(fs3[1]);
     QVERIFY(f4!=f5);
     QhullFacet f6(fs3[2]);
     QhullFacet f7(fs3[3]);
     QCOMPARE(i2.peekPrevious(), f7);
     QCOMPARE(i2.previous(), f7);
     QCOMPARE(i2.previous(), f6);
     QCOMPARE(i2.previous(), f5);
     QCOMPARE(i2.previous(), f4);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), f4);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), f4);
     QCOMPARE(i.peekNext(), f5);
     QCOMPARE(i.next(), f5);
     QCOMPARE(i.next(), f6);
     QCOMPARE(i.next(), f7);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), f4);
 }//t_qhullset_iterator
 
 void QhullSet_test::
 t_io()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     // Fake an empty set.  Default constructor not defined.  No memory allocation.
     QhullFacet f= q.beginFacet();
     QhullFacetSet fs= f.neighborFacets();
     fs.defineAs(q.qhullQh()->other_points);
     cout << "INFO:     empty set" << fs << std::endl;
     QhullFacet f2= q.beginFacet();
     QhullFacetSet fs2= f2.neighborFacets();
     cout << "INFO:   Neighboring facets\n";
     cout << fs2 << std::endl;
 
     QhullRidgeSet rs= f.ridges();
     cout << "INFO:   Ridges for a facet\n";
     cout << rs << std::endl;
 }//t_io
 
 }//namespace orgQhull
 
 #include "moc/QhullSet_test.moc"
diff --git a/src/qhullptest/QhullVertexSet_test.cpp b/src/qhullptest/QhullVertexSet_test.cpp
index b56780f..e8f950e 100644
--- a/src/qhullptest/QhullVertexSet_test.cpp
+++ b/src/qhullptest/QhullVertexSet_test.cpp
@@ -1,185 +1,185 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullVertexSet_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullVertexSet_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include 
 #include "../road/RoadTest.h" // FIXUP First for QHULL_USES_QT
 
 #include "Qhull.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacetSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_foreach();
     void t_io();
 };//QhullFacetSet_test
 
 void
 add_QhullFacetSet_test()
 {
     new QhullFacetSet_test();
 }
 
 //Executed after each testcase
 void QhullFacetSet_test::
 cleanup()
 {
     RoadTest::cleanup();
     UsingQhullLib::checkQhullMemoryEmpty();
 }
 
 void QhullFacetSet_test::
 t_construct()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullFacetSet fs2= f.neighborFacets();
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),4);
     QhullFacetSet fs4= fs2; // copy constructor
     QVERIFY(fs4==fs2);
     QhullFacetSet fs3(q.qhullQh()->facet_mergeset);
     QVERIFY(fs3.isEmpty());
 }//t_construct
 
 void QhullFacetSet_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0 QV2");  // rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullFacetSet fs2= f.neighborFacets();
     QVERIFY(!fs2.isSelectAll());
     QCOMPARE(fs2.count(),2);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 2u);
     QList fv2= fs2.toQList();
     QCOMPARE(fv2.size(), 2);
     fs2.selectAll();
     QVERIFY(fs2.isSelectAll());
     std::vector fv3= fs2.toStdVector();
     QCOMPARE(fv3.size(), 4u);
     QList fv4= fs2.toQList();
     QCOMPARE(fv4.size(), 4);
 }//t_convert
 
 //! Spot check properties and read-only.  See QhullSet_test
 void QhullFacetSet_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 4);
     fs.selectGood();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     QhullFacet f= fs.first();
     QhullFacet f2= fs.last();
     fs.selectAll();
     QVERIFY(fs.contains(f));
     QVERIFY(fs.contains(f2));
     QVERIFY(f.isGood());
     QVERIFY(!f2.isGood());
     fs.selectGood();
     QVERIFY(fs.contains(f));
     QVERIFY(!fs.contains(f2));
 }//t_readonly
 
 void QhullFacetSet_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     // Spot check predicates and accessors.  See QhullLinkedList_test
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.contains(q.firstFacet()));
     QVERIFY(fs.contains(fs.first()));
     QhullFacet f= q.firstFacet().next();
     if(!fs.contains(f)){
         f= f.next();
     }
     QVERIFY(fs.contains(f));
     QCOMPARE(fs.first(), *fs.begin());
     QCOMPARE(*(fs.end()-1), fs.last());
 }//t_foreach
 
 void QhullFacetSet_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
         QhullFacetSet fs= q.firstFacet().neighborFacets();
         ostringstream os;
         os << fs.print(q.runId(), "Neighbors of first facet with point 0");
         os << fs.printIdentifiers("\nFacet identifiers: ");
         cout<< os.str();
         QString facets= QString::fromStdString(os.str());
         QCOMPARE(facets.count(QRegExp(" f[0-9]")), 2+13*2);
     }
 }//t_io
 
 //FIXUP -- Move conditional, QhullFacetSet code to QhullFacetSet.cpp
 #ifndef QHULL_NO_STL
 std::vector QhullFacetSet::
 toStdVector() const
 {
     QhullSetIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.push_back(f);
         }
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #ifdef QHULL_USES_QT
 QList QhullFacetSet::
 toQList() const
 {
     QhullSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.append(f);
         }
     }
     return vs;
 }//toQList
 #endif //QHULL_USES_QT
 
 }//orgQhull
 
 #include "moc/QhullFacetSet_test.moc"
diff --git a/src/qhullptest/QhullVertex_test.cpp b/src/qhullptest/QhullVertex_test.cpp
index 2ac9522..078d872 100644
--- a/src/qhullptest/QhullVertex_test.cpp
+++ b/src/qhullptest/QhullVertex_test.cpp
@@ -1,184 +1,184 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/QhullVertex_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/QhullVertex_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullVertex.h"
 #include "Coordinates.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 #include "QhullVertexSet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullVertex_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_constructConvert();
     void t_getSet();
     void t_foreach();
     void t_io();
 };//QhullVertex_test
 
 void
 add_QhullVertex_test()
 {
     new QhullVertex_test();
 }
 
 //Executed after each testcase
 void QhullVertex_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullVertex_test::
 t_constructConvert()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullVertex v;
     QVERIFY(!v.isDefined());
     QCOMPARE(v.dimension(),0);
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullVertex v2(q.beginVertex());
     QCOMPARE(v2.dimension(),3);
     v= v2;  // copy assignment
     QVERIFY(v.isDefined());
     QCOMPARE(v.dimension(),3);
     QhullVertex v5= v2; // copy constructor
     QVERIFY(v5==v2);
     QVERIFY(v5==v);
     QhullVertex v3= v2.getVertexT();
     QCOMPARE(v,v3);
     QhullVertex v4= v2.getBaseT();
     QCOMPARE(v,v4);
 }//t_constructConvert
 
 void QhullVertex_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QCOMPARE(q.vertexCount(), 8);
 
         // Also spot-test QhullVertexList.  See QhullLinkedList_test.cpp
         QhullVertexList vs= q.vertexList();
         QhullVertexListIterator i(vs);
         while(i.hasNext()){
             const QhullVertex v= i.next();
             cout << v.id() << endl;
             QCOMPARE(v.dimension(),3);
             QVERIFY(v.id()>=0 && v.id()<9);
             QVERIFY(v.isDefined());
             if(i.hasNext()){
                 QCOMPARE(v.next(), i.peekNext());
                 QVERIFY(v.next()!=v);
                 QVERIFY(v.next().previous()==v);
             }
             QVERIFY(i.hasPrevious());
             QCOMPARE(v, i.peekPrevious());
         }
         QhullVertexListIterator i2(i);
         QEXPECT_FAIL("", "ListIterator copy constructor not reset to BOT", Continue);
         QVERIFY(!i2.hasPrevious());
 
         // test point()
         foreach (QhullVertex v, q.vertexList()){  // Qt only
             QhullPoint p= v.point();
             int j= p.id(q.runId());
             cout << "Point " << j << ":\n" << p.print(q.runId()) << endl;
             QVERIFY(j>=0 && j<8);
         }
     }
 }//t_getSet
 
 void QhullVertex_test::
 t_foreach()
 {
     RboxPoints rcube("c W0 300");  // 300 points on surface of cube
     {
         Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube
         foreach (QhullVertex v, q.vertexList()){  // Qt only
             QhullFacetSet fs= v.neighborFacets();
             QCOMPARE(fs.count(), 3);
             foreach (QhullFacet f, fs){  // Qt only
                 QVERIFY(f.vertices().contains(v));
             }
         }
     }
 }//t_foreach
 
 void QhullVertex_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullVertex v= q.beginVertex();
         ostringstream os;
         os << "Vertex and vertices w/o runId:\n";
         os << v;
         QhullVertexSet vs= q.firstFacet().vertices();
         os << vs;
         os << "Vertex and vertices w/ runId:\n";
         os << v.print(q.runId());
         os << vs.print(q.runId(), "vertices:");
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("(v"), 10);
         QCOMPARE(s.count(": f"), 2);
     }
     RboxPoints r10("10 D3");  // Without QhullVertex::facetNeighbors
     {
         Qhull q(r10, "");
         QhullVertex v= q.beginVertex();
         ostringstream os;
         os << "\nTry again with simplicial facets.  No neighboring facets listed for vertices.\n";
         os << "Vertex and vertices w/o runId:\n";
         os << v;
         q.defineVertexNeighborFacets();
         os << "This time with neighborFacets() defined for all vertices:\n";
         os << v;
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count(": f"), 1);
 
         Qhull q2(r10, "v"); // Voronoi diagram
         QhullVertex v2= q2.beginVertex();
         ostringstream os2;
         os2 << "\nTry again with Voronoi diagram of simplicial facets.  Neighboring facets automatically defined for vertices.\n";
         os2 << "Vertex and vertices w/o runId:\n";
         os2 << v2;
         cout << os2.str();
         QString s2= QString::fromStdString(os2.str());
         QCOMPARE(s2.count(": f"), 1);
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullVertex_test.moc"
diff --git a/src/qhullptest/Qhull_test.cpp b/src/qhullptest/Qhull_test.cpp
index 5bbd2fe..69507d8 100644
--- a/src/qhullptest/Qhull_test.cpp
+++ b/src/qhullptest/Qhull_test.cpp
@@ -1,380 +1,380 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/Qhull_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/Qhull_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "Qhull.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacetList.h"
 
 using std::cout;
 using std::endl;
 using std::string;
 
 namespace orgQhull {
 
 //! Test C++ interface to Qhull
 //! See eg/q_test for tests of Qhull commands
 class Qhull_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_attribute();
     void t_message();
     void t_getSet();
     void t_getQh();
     void t_getValue();
     void t_foreach();
     void t_modify();
 };//Qhull_test
 
 void
 add_Qhull_test()
 {
     new Qhull_test();
 }
 
 //Executed after each testcase
 void Qhull_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void Qhull_test::
 t_construct()
 {
     {
         Qhull q;
         QCOMPARE(q.dimension(),0);
         QVERIFY(q.qhullQh()!=0);
         QVERIFY(q.runId()!=0);
         QCOMPARE(QString(q.qhullCommand()),QString(""));
         QCOMPARE(QString(q.rboxCommand()),QString(""));
         try{
             QCOMPARE(q.area(),0.0);
             QFAIL("area() did not fail.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         Qhull q2(q);  // Copy constructor and copy assignment OK if not q.initialized()
         QCOMPARE(q2.dimension(),0);
         q= q2;
         QCOMPARE(q.dimension(),0);
     }
     {
         RboxPoints rbox("10000");
         Qhull q(rbox, "QR0"); // Random points in a randomly rotated cube.
         QCOMPARE(q.dimension(),3);
         QVERIFY(q.volume() < 1.0);
         QVERIFY(q.volume() > 0.99);
         try{
             Qhull q2(q);
             QFAIL("Copy constructor did not fail for initialized Qhull.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         try{
             Qhull q3;
             q3= q;
             QFAIL("Copy assignment did not fail for initialized Qhull source.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         QCOMPARE(q.dimension(),3);
         try{
             Qhull q4;
             q= q4;
             QFAIL("Copy assignment did not fail for initialized Qhull destination.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         QCOMPARE(q.dimension(),3);
     }
     {
         double points[] = {
             0, 0,
             1, 0,
             1, 1
         };
         Qhull q("triangle", 2, 3, points, "");
         QCOMPARE(q.dimension(),2);
         QCOMPARE(q.facetCount(),3);
         QCOMPARE(q.vertexCount(),3);
         QCOMPARE(q.dimension(),2);
         QCOMPARE(q.area(), 2.0+sqrt(2.0)); // length of boundary
         QCOMPARE(q.volume(), 0.5);        // the 2-d area
     }
 }//t_construct
 
 void Qhull_test::
 t_attribute()
 {
     RboxPoints rcube("c");
     {
         double normals[] = {
             0,  -1, -0.5,
            -1,   0, -0.5,
             1,   0, -0.5,
             0,   1, -0.5
         };
         Qhull q;
         q.feasiblePoint << 0.0 << 0.0;
         Coordinates c(std::vector(2, 0.0));
         QVERIFY(q.feasiblePoint==c);
         q.setOutputStream(&cout);
         q.runQhull("normals of square", 3, 4, normals, "H"); // halfspace intersect
         QCOMPARE(q.facetList().count(), 4); // Vertices of square
         cout << "Expecting summary of halfspace intersect\n";
         q.outputQhull();
         q.useOutputStream= false;
         cout << "Expecting no output from qh_fprintf() in Qhull.cpp\n";
         q.outputQhull();
     }
 }//t_attribute
 
 //! No QhullMessage for errors outside of qhull
 void Qhull_test::
 t_message()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         QCOMPARE(q.qhullMessage(), string(""));
         QCOMPARE(q.qhullStatus(), qh_ERRnone);
         QVERIFY(!q.hasQhullMessage());
         try{
             q.runQhull(rcube, "Fd");
             QFAIL("runQhull Fd did not fail.");
         }catch (const std::exception &e) {
             const char *s= e.what();
             cout << "INFO   : Caught " << s;
             QCOMPARE(QString::fromStdString(s).left(6), QString("QH6029"));
             // FIXUP QH11025 -- review decision to clearQhullMessage at QhullError()            // Cleared when copied to QhullError
             QVERIFY(!q.hasQhullMessage());
             // QCOMPARE(q.qhullMessage(), QString::fromStdString(s).remove(0, 7));
             // QCOMPARE(q.qhullStatus(), 6029);
             q.clearQhullMessage();
             QVERIFY(!q.hasQhullMessage());
         }
         q.appendQhullMessage("Append 1");
         QVERIFY(q.hasQhullMessage());
         QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1"));
         q.appendQhullMessage("\nAppend 2\n");
         QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1\nAppend 2\n"));
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
         QCOMPARE(QString::fromStdString(q.qhullMessage()), QString(""));
     }
     {
         cout << "INFO   : Error stream without output stream\n";
         Qhull q;
         q.setErrorStream(&cout);
         q.setOutputStream(0);
         try{
             q.runQhull(rcube, "Fd");
             QFAIL("runQhull Fd did not fail.");
         }catch (const QhullError &e) {
             cout << "INFO   : Caught " << e;
             QCOMPARE(e.errorCode(), 6029);
         }
         //FIXUP QH11026 Qhullmessage cleared when QhullError thrown.  Switched to e
         //QVERIFY(q.hasQhullMessage());
         //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(6), QString("QH6029"));
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
     }
     {
         cout << "INFO   : Error output sent to output stream without error stream\n";
         Qhull q;
         q.setErrorStream(0);
         q.setOutputStream(&cout);
         try{
             q.runQhull(rcube, "Tz H0");
             QFAIL("runQhull TZ did not fail.");
         }catch (const std::exception &e) {
             const char *s= e.what();
             cout << "INFO   : Caught " << s;
             QCOMPARE(QString::fromAscii(s).left(6), QString("QH6023"));
         }
         //FIXUP QH11026 Qhullmessage cleared when QhullError thrown.  Switched to e
         //QVERIFY(q.hasQhullMessage());
         //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(17), QString("qhull: no message"));
         //QCOMPARE(q.qhullStatus(), 6023);
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
     }
     {
         cout << "INFO   : No error stream or output stream\n";
         Qhull q;
         q.setErrorStream(0);
         q.setOutputStream(0);
         try{
             q.runQhull(rcube, "Fd");
             QFAIL("outputQhull did not fail.");
         }catch (const std::exception &e) {
             const char *s= e.what();
             cout << "INFO   : Caught " << s;
             QCOMPARE(QString::fromAscii(s).left(6), QString("QH6029"));
         }
         //FIXUP QH11026 Qhullmessage cleared when QhullError thrown.  Switched to e
         //QVERIFY(q.hasQhullMessage());
         //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(9), QString("qhull err"));
         //QCOMPARE(q.qhullStatus(), 6029);
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
     }
 }//t_message
 
 void Qhull_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         QVERIFY(!q.initialized());
         q.runQhull(rcube, "s");
         QVERIFY(q.initialized());
         QCOMPARE(q.dimension(), 3);
         QhullPoint p= q.origin();
         QCOMPARE(p.dimension(), 3);
         QCOMPARE(p[0]+p[1]+p[2], 0.0);
         QVERIFY(q.runId()!=0);
         q.setErrorStream(&cout);
         q.outputQhull();
     }
     {
         Qhull q;
         q.runQhull(rcube, "");
         q.setOutputStream(&cout);
         q.outputQhull();
     }
     // qhullQh -- UsingLibQhull [Qhull.cpp]
     // runId -- UsingLibQhull [Qhull.cpp]
 }//t_getSet
 
 void Qhull_test::
 t_getQh()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         q.runQhull(rcube, "s");
         QCOMPARE(QString(q.qhullCommand()), QString("qhull s"));
         QCOMPARE(QString(q.rboxCommand()), QString("rbox \"c\""));
         QCOMPARE(q.facetCount(), 6);
         QCOMPARE(q.vertexCount(), 8);
         // Sample fields from Qhull's qhT [libqhull.h]
         QCOMPARE(q.qhullQh()->ALLpoints, 0u);
         QCOMPARE(q.qhullQh()->GOODpoint, 0);
         QCOMPARE(q.qhullQh()->IStracing, 0);
         QCOMPARE(q.qhullQh()->MAXcoplanar+1.0, 1.0); // fuzzy compare
         QCOMPARE(q.qhullQh()->MERGING, 1u);
         QCOMPARE(q.qhullQh()->input_dim, 3);
         QCOMPARE(QString(q.qhullQh()->qhull_options).left(8), QString("  run-id"));
         QCOMPARE(q.qhullQh()->run_id, q.runId());
         QCOMPARE(q.qhullQh()->num_facets, 6);
         QCOMPARE(q.qhullQh()->hasTriangulation, 0u);
         QCOMPARE(q.qhullQh()->max_outside - q.qhullQh()->min_vertex + 1.0, 1.0); // fuzzy compare
         QCOMPARE(*q.qhullQh()->gm_matrix+1.0, 1.0); // fuzzy compare
     }
 }//t_getQh
 
 void Qhull_test::
 t_getValue()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         q.runQhull(rcube, "");
         QCOMPARE(q.area(), 6.0);
         QCOMPARE(q.volume(), 1.0);
     }
 }//t_getValue
 
 void Qhull_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         QCOMPARE(q.beginFacet(),q.endFacet());
         QCOMPARE(q.beginVertex(),q.endVertex());
         q.runQhull(rcube, "");
         QCOMPARE(q.facetList().count(), 6);
 
         // defineVertexNeighborFacets() tested in QhullVertex_test::t_io()
 
         QhullFacetList facets(q.beginFacet(), q.endFacet());
         QCOMPARE(facets.count(), 6);
         QCOMPARE(q.firstFacet(), q.beginFacet());
         QhullVertexList vertices(q.beginVertex(), q.endVertex());
         QCOMPARE(vertices.count(), 8);
         QCOMPARE(q.firstVertex(), q.beginVertex());
         QhullPoints ps= q.points();
         QCOMPARE(ps.count(), 8);
         QhullPointSet ps2= q.otherPoints();
         QCOMPARE(ps2.count(), 0);
         // ps2= q.otherPoints(); //disabled, would not copy the points
         QCOMPARE(q.facetCount(), 6);
         QCOMPARE(q.vertexCount(), 8);
         coordT *c= q.pointCoordinateBegin(); // of q.points()
         QVERIFY(*c==0.5 || *c==-0.5);
         coordT *c3= q.pointCoordinateEnd();
         QVERIFY(c3[-1]==0.5 || c3[-1]==-0.5);
         QCOMPARE(c3-c, 8*3);
         QCOMPARE(q.vertexList().count(), 8);
     }
 }//t_foreach
 
 void Qhull_test::
 t_modify()
 {
     //addPoint() tested in t_foreach
     RboxPoints diamond("d");
     Qhull q(diamond, "o");
     q.setOutputStream(&cout);
     cout << "Expecting vertexList and facetList of a 3-d diamond.\n";
     q.outputQhull();
     cout << "Expecting normals of a 3-d diamond.\n";
     q.outputQhull("n");
     // runQhull tested in t_attribute(), t_message(), etc.
 }//t_modify
 
 }//orgQhull
 
 // Redefine Qhull's usermem.c
 void qh_exit(int exitcode) {
     cout << "FAIL!  : Qhull called qh_exit().  Qhull's error handling not available.\n.. See the corresponding Qhull:qhull_message or setErrorStream().\n";
     exit(exitcode);
 }
 void qh_free(void *mem) {
     free(mem);
 }
 void *qh_malloc(size_t size) {
     return malloc(size);
 }
 
 #if 0
 template<> char * QTest::
 toString(const std::string &s)
 {
     QByteArray ba = s.c_str();
     return qstrdup(ba.data());
 }
 #endif
 
 #include "moc/Qhull_test.moc"
diff --git a/src/qhullptest/RboxPoints_test.cpp b/src/qhullptest/RboxPoints_test.cpp
index aca7c1b..161be97 100644
--- a/src/qhullptest/RboxPoints_test.cpp
+++ b/src/qhullptest/RboxPoints_test.cpp
@@ -1,216 +1,216 @@
 /****************************************************************************
 **
-** Copyright (c) 2006-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/RboxPoints_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2006-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/RboxPoints_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "RboxPoints.h"
 #include "QhullError.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::string;
 using std::stringstream;
 
 namespace orgQhull {
 
 //! Test C++ interface to Rbox
 //! See eg/q_test for tests of rbox commands
 class RboxPoints_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void t_construct();
     void t_error();
     void t_test();
     void t_getSet();
     void t_foreach();
     void t_change();
     void t_ostream();
 };
 
 void
 add_RboxPoints_test()
 {
     new RboxPoints_test();
 }
 
 void RboxPoints_test::
 t_construct()
 {
     RboxPoints rp;
     QCOMPARE(rp.dimension(), 0);
     QCOMPARE(rp.count(), 0);
     QVERIFY(QString::fromStdString(rp.comment()) != QString(""));
     QVERIFY(rp.isEmpty());
     QVERIFY(!rp.hasRboxMessage());
     QCOMPARE(rp.rboxStatus(), qh_ERRnone);
     QCOMPARE(QString::fromStdString(rp.rboxMessage()), QString("rbox warning: no points generated\n"));
 
     RboxPoints rp2("c"); // 3-d cube
     QCOMPARE(rp2.dimension(), 3);
     QCOMPARE(rp2.count(), 8);
     QCOMPARE(QString::fromStdString(rp2.comment()), QString("rbox \"c\""));
     QVERIFY(!rp2.isEmpty());
     QVERIFY(!rp2.hasRboxMessage());
     QCOMPARE(rp2.rboxStatus(), qh_ERRnone);
     QCOMPARE(QString::fromStdString(rp2.rboxMessage()), QString("rbox: OK\n"));
 }//t_construct
 
 void RboxPoints_test::
 t_error()
 {
     RboxPoints rp;
     try{
         rp.appendPoints("D0 c");
         QFAIL("'D0 c' did not fail.");
     }catch (const std::exception &e) {
         const char *s= e.what();
         cout << "INFO   : Caught " << s;
         QCOMPARE(QString(s).left(6), QString("QH6189"));
         QVERIFY(rp.hasRboxMessage());
         QCOMPARE(QString::fromStdString(rp.rboxMessage()).left(8), QString("rbox err"));
         QCOMPARE(rp.rboxStatus(), 6189);
         rp.clearRboxMessage();
         QVERIFY(!rp.hasRboxMessage());
     }
     try{
         RboxPoints rp2;
         rp2.setDimension(-1);
         QFAIL("setDimension(-1) did not fail.");
     }catch (const RoadError &e) {
         const char *s= e.what();
         cout << "INFO   : Caught " << s;
         QCOMPARE(QString(s).left(7), QString("QH10062"));
         QCOMPARE(e.errorCode(), 10062);
         QCOMPARE(QString::fromStdString(e.what()), QString(s));
         RoadLogEvent logEvent= e.roadLogEvent();
         QCOMPARE(logEvent.int1(), -1);
     }
 }//t_error
 
 void RboxPoints_test::
 t_test()
 {
     // isEmpty -- t_construct
 }//t_test
 
 void RboxPoints_test::
 t_getSet()
 {
     // comment -- t_construct
     // count -- t_construct
     // dimension -- t_construct
 
     RboxPoints rp;
     QCOMPARE(rp.dimension(), 0);
     rp.setDimension(2);
     QCOMPARE(rp.dimension(), 2);
     rp.setDimension(2);
     QCOMPARE(rp.dimension(), 2);
     try{
         rp.setDimension(102);
         QFAIL("setDimension(102) did not fail.");
     }catch (const std::exception &e) {
         cout << "INFO   : Caught " << e.what();
     }
     QCOMPARE(rp.newCount(), 0);
     rp.appendPoints("D2 P1 P2");
     QCOMPARE(rp.count(), 2);
     QCOMPARE(rp.newCount(), 2); // From previous appendPoints();
     PointCoordinates pc(2);
     pc << 1.0 << 0.0 << 2.0 << 0.0;
     QCOMPARE(pc.dimension(), 2);
     QCOMPARE(pc.count(), 2);
     QVERIFY(rp==pc);
     rp.setNewCount(10);  // Normally only used by appendPoints for rbox processing
     QCOMPARE(rp.newCount(), 10);
     rp.reservePoints();
     QVERIFY(rp==pc);
 }//t_getSet
 
 void RboxPoints_test::
 t_foreach()
 {
     RboxPoints rp("c");
     Coordinates::ConstIterator cci= rp.beginCoordinates();
     orgQhull::Coordinates::Iterator ci= rp.beginCoordinates();
     QCOMPARE(*cci, -0.5);
     QCOMPARE(*ci, *cci);
     int i=1;
     while(++cci
 #include 
 #include "RoadTest.h"
 
 using std::cout;
 using std::endl;
 
 namespace orgQhull {
 
 #//class variable
 
 QList RoadTest::
 s_testcases;
 
 int RoadTest::
 s_test_count= 0;
 
 int RoadTest::
 s_test_fail= 0;
 
 QStringList RoadTest::
 s_failed_tests;
 
 #//Slot
 
 //! Executed after each test
 void RoadTest::
 cleanup()
 {
     s_test_count++;
     if(QTest::currentTestFailed()){
         recordFailedTest();
     }
 }//cleanup
 
 #//Helper
 
 void RoadTest::
 recordFailedTest()
 {
     s_test_fail++;
     QString className= metaObject()->className();
     s_failed_tests << className + "::" + QTest::currentTestFunction();
 }
 
 #//class function
 
 int RoadTest::
 runTests(QStringList arguments)
 {
     int result= 0; // assume success
 
     foreach(RoadTest *testcase, s_testcases){
         try{
             result += QTest::qExec(testcase, arguments);
         }catch(const std::exception &e){
             cout << "FAIL!  : Threw error ";
             cout << e.what() << endl;
     s_test_count++;
             testcase->recordFailedTest();
             // Qt 4.5.2 OK.  In Qt 4.3.3, qtestcase did not clear currentTestObject
         }
     }
     if(s_test_fail){
         cout << "Failed " << s_test_fail << " of " << s_test_count << " tests.\n";
         cout << s_failed_tests.join("\n").toLocal8Bit().constData() << std::endl;
     }else{
         cout << "Passed " << s_test_count << " tests.\n";
     }
     return result;
 }//runTests
 
 }//orgQhull
 
 #include "moc/moc_RoadTest.cpp"
diff --git a/src/qhullptest/RoadTest.h b/src/qhullptest/RoadTest.h
index 4826711..fc3a2d4 100644
--- a/src/qhullptest/RoadTest.h
+++ b/src/qhullptest/RoadTest.h
@@ -1,101 +1,101 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/RoadTest.h#1 $$Change: 1652 $
-** $Date: 2014/01/17 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/RoadTest.h#2 $$Change: 1810 $
+** $Date: 2015/01/17 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef ROADTEST_H
 #define ROADTEST_H
 
 //pre-compiled with RoadTest.h
 #include     // Qt C++ Framework
 #include 
 
 #define QHULL_USES_QT 1
 
 namespace orgQhull {
 
 #//!\name Defined here
 
     //! RoadTest -- Generic test for Qt's QTest
     class RoadTest;
     //! TESTadd_(t) -- Add a RoadTest
 
 /** Test Name objects using Qt's QTestLib
 
 Template:
 
 class Name_test : public RoadTest
 {
     Q_OBJECT
 #//Test slot
 private slots:
     void t_name();
     //Executed before any test
     void initTestCase();
     void init();          // Each test
     //Executed after each test
     void cleanup(); //RoadTest::cleanup();
     // Executed after last test
     void cleanupTestCase();
 };
 
 void
 add_Name_test()
 {
     new Name_test();
 }
 
 Send additional output to cout
 */
 
 class RoadTest : public QObject
 {
     Q_OBJECT
 
 #//!\name Class globals
 protected:
     static QList
                         s_testcases; ///! List of testcases to execute.  Initialized via add_...()
     static int          s_test_count; ///! Total number of tests executed
     static int          s_test_fail; ///! Number of failed tests
     static QStringList  s_failed_tests; ///! List of failed tests
 
 #//!\name Test slots
 public slots:
     void cleanup();
 
 public:
 #//!\name Constructors, etc.
     RoadTest()  { s_testcases.append(this); }
     ~RoadTest() { s_testcases.removeAll(this); }
 
 #//Helper
     void                recordFailedTest();
 
 
 #//!\name Class functions
     static int          runTests(QStringList arguments);
 
 };//RoadTest
 
 #define TESTadd_(t) extern void t(); t();
 
 
 }//orgQhull
 
 namespace QTest{
 
 template<>
 inline char *
 toString(const std::string &s)
 {
     return qstrdup(s.c_str());
 }
 
 }//namespace QTest
 
 #endif //ROADTEST_H
 
diff --git a/src/qhullptest/UsingLibQhull_test.cpp b/src/qhullptest/UsingLibQhull_test.cpp
index 3c4f529..4fe94b4 100644
--- a/src/qhullptest/UsingLibQhull_test.cpp
+++ b/src/qhullptest/UsingLibQhull_test.cpp
@@ -1,210 +1,210 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/UsingLibQhull_test.cpp#1 $$Change: 1652 $
-** $DateTime: 2014/01/17 09:01:32 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/UsingLibQhull_test.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "UsingLibQhull.h"
 #include "QhullError.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::string;
 
 namespace orgQhull {
 
 //! Test C++ interface to Qhull
 //! See eg/q_test for tests of Qhull commands
 class UsingLibQhull_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_classMembers();
     void t_globalPoints();
     void t_UsingLibQhull();
     void t_methods();
     void t_cleanuptestcase();
 };//UsingLibQhull_test
 
 void
 add_UsingLibQhull_test()
 {
     new UsingLibQhull_test();
 }
 
 //Executed after each testcase
 void UsingLibQhull_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void UsingLibQhull_test::
 t_classMembers()
 {
     {
         //checkQhullMemoryEmpty tested by cleanup()
         QCOMPARE(UsingLibQhull::globalMachineEpsilon()+1.0, 1.0);
         RboxPoints r10("10");
         Qhull q(r10,"v");  // voronoi diagram of 10 points
         UsingLibQhull::unsetGlobalAngleEpsilon();
         UsingLibQhull::unsetGlobalDistanceEpsilon();
         cout << "MachineEpsilon " << UsingLibQhull::globalMachineEpsilon()
             << " angleEpsilon " << UsingLibQhull::globalAngleEpsilon()
             << " distanceEpsilon " << UsingLibQhull::globalDistanceEpsilon()
             << endl;
         QCOMPARE(UsingLibQhull::currentAngleEpsilon()+1.0, 1.0);
         QVERIFY(UsingLibQhull::currentAngleEpsilon() > UsingLibQhull::globalMachineEpsilon());
         QCOMPARE(UsingLibQhull::currentDistanceEpsilon()+1.0, 1.0);
         QVERIFY(UsingLibQhull::currentDistanceEpsilon() >= UsingLibQhull::currentAngleEpsilon());
         QCOMPARE(UsingLibQhull::currentQhull().runId(), q.runId());
         QCOMPARE(UsingLibQhull::globalAngleEpsilon()+1.0, UsingLibQhull::currentAngleEpsilon()+1.0);
         QCOMPARE(UsingLibQhull::currentVertexDimension(), q.dimension());
         QCOMPARE(UsingLibQhull::globalDistanceEpsilon()+1.0, UsingLibQhull::currentDistanceEpsilon()+1.0);
         UsingLibQhull::setGlobalAngleEpsilon(1.0);
         UsingLibQhull::setGlobalDistanceEpsilon(1.0);
         cout << " Global angleEpsilon " << UsingLibQhull::globalAngleEpsilon()
             << " distanceEpsilon " << UsingLibQhull::globalDistanceEpsilon()
             << endl;
         QCOMPARE(UsingLibQhull::globalAngleEpsilon(), UsingLibQhull::globalDistanceEpsilon());
         QVERIFY(UsingLibQhull::currentAngleEpsilon() != UsingLibQhull::globalAngleEpsilon());
         UsingLibQhull::setGlobalVertexDimension(3);
         QCOMPARE(UsingLibQhull::globalVertexDimension(), UsingLibQhull::currentVertexDimension());
         UsingLibQhull::setGlobalVertexDimension(2);
         QCOMPARE(UsingLibQhull::globalVertexDimension(), 2);
         QCOMPARE(UsingLibQhull::currentVertexDimension(), q.dimension());
         QVERIFY(UsingLibQhull::currentDistanceEpsilon() != UsingLibQhull::globalDistanceEpsilon());
         UsingLibQhull::unsetGlobalAngleEpsilon();
         UsingLibQhull::unsetGlobalVertexDimension();
         UsingLibQhull::unsetGlobalDistanceEpsilon();
         QCOMPARE(UsingLibQhull::currentAngleEpsilon()+1.0, UsingLibQhull::globalAngleEpsilon()+1.0);
         QCOMPARE(UsingLibQhull::globalVertexDimension(), UsingLibQhull::currentVertexDimension());
         QCOMPARE(UsingLibQhull::currentDistanceEpsilon()+1.0, UsingLibQhull::globalDistanceEpsilon()+1.0);
         UsingLibQhull::setGlobals();
     }
     QCOMPARE(UsingLibQhull::globalAngleEpsilon()+1.0, 1.0);
     QCOMPARE(UsingLibQhull::globalVertexDimension(), 4); // 'v'.  VertexDimension is only used for QhullVertex where dim>15
     QCOMPARE(UsingLibQhull::globalDistanceEpsilon()+1.0, 1.0);
     UsingLibQhull::unsetGlobals();
     try{
         cout << UsingLibQhull::globalVertexDimension();
         QFAIL("Did not throw error for undefined dimension.");
     }catch(const std::exception &e){
         cout << "INFO     Caught error -- " << e.what() << endl;
     }
 }//t_classMembers
 
 void UsingLibQhull_test::
 t_globalPoints()
 {
     const coordT *r10PointsBegin;
     {
         RboxPoints r10("10");
         Qhull q(r10,"v");  // voronoi diagram of 10 points
         UsingLibQhull::unsetGlobalPoints();
         int dimension;
         const coordT *pointsEnd;
         const coordT *pointsBegin= UsingLibQhull::globalPoints(&dimension, &pointsEnd);
         cout << "pointsBegin " << pointsBegin
             << " pointsEnd " << pointsEnd
             << " dimension " << dimension
             << endl;
         int dimension2;
         const coordT *pointsEnd2;
         const coordT *pointsBegin2= UsingLibQhull::currentPoints(&dimension2, &pointsEnd2);
         QCOMPARE(pointsBegin2, pointsBegin);
         QCOMPARE(pointsEnd2, pointsEnd);
         QCOMPARE(dimension2, dimension);
         coordT c[]= { 1.0,2.0, 3.0,4.0, 5.0,6.0 };
         UsingLibQhull::setGlobalPoints(2, c, c+3*2);
         pointsBegin= UsingLibQhull::globalPoints(&dimension, &pointsEnd);
         QCOMPARE(pointsBegin, c);
         QCOMPARE(pointsEnd[-1], 6.0);
         QCOMPARE(dimension, 2);
         UsingLibQhull::unsetGlobalPoints();
         pointsBegin= UsingLibQhull::globalPoints(&dimension, &pointsEnd);
         QCOMPARE(pointsBegin, pointsBegin2);
         QCOMPARE(pointsEnd, pointsEnd2);
         QCOMPARE(dimension, dimension2);
         UsingLibQhull::setGlobals();
         r10PointsBegin= pointsBegin;
     }
     int dimension3;
     const coordT *pointsEnd3;
     const coordT *pointsBegin3= UsingLibQhull::currentPoints(&dimension3, &pointsEnd3);
     QCOMPARE(pointsBegin3, r10PointsBegin); // Memory was freed
     QCOMPARE(pointsEnd3, r10PointsBegin+10*4);
     QCOMPARE(dimension3, 4);
     UsingLibQhull::unsetGlobals();
     try{
         pointsBegin3= UsingLibQhull::globalPoints(&dimension3, &pointsEnd3);
         QFAIL("Did not throw error for undefined global points.");
     }catch(const std::exception &e){
         cout << "INFO     Caught error -- " << e.what() << endl;
     }
 }//t_globalPoints
 
 void UsingLibQhull_test::
 t_UsingLibQhull()
 {
     {
         Qhull q;
         UsingLibQhull uq(&q); // Normally created in a method using 'this'
 
         try{
             Qhull q2; // If qh_QHpointer, QhullQh() calls usinlibqhull()
             UsingLibQhull uq2(&q2);
             QFAIL("UsingLibQhull did not fail.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
     }
     Qhull q3;
     UsingLibQhull uq3(&q3);
     // UsingLibQhull uq4; // Default constructors disabled.
 }//t_UsingLibQhull
 
 void UsingLibQhull_test::
 t_methods()
 {
     Qhull q;
     UsingLibQhull u(&q); // Normally created in a method using 'this'
     QVERIFY(u.defined());
     u.maybeThrowQhullMessage(0);  // Nothing thrown
     try{
         u.maybeThrowQhullMessage(1);
         QFAIL("maybeThrowQhullMessage(1) did not fail.");
     }catch (const std::exception &e) {
         cout << "INFO   : Caught " << e.what();
     }
     // Can not check checkRunId() in maybeThrowQhullMessage().  Requires another thread.
     u.maybeThrowQhullMessage(2, UsingLibQhull::NOthrow);
     try{
         throw QhullError(10054, "Report previous NOthrow error");
     }catch (const std::exception &e) {
         cout << "INFO   : " << e.what();
     }
 }//t_methods
 
 // Executed after last test
 void UsingLibQhull_test::
 t_cleanuptestcase()
 {
     UsingLibQhull::unsetGlobals();
 }//t_cleanuptestcase
 
 }//orgQhull
 
 #include "moc/UsingLibQhull_test.moc"
 
diff --git a/src/qhullptest/qhullptest.cpp b/src/qhullptest/qhullptest.cpp
index f095254..059e350 100644
--- a/src/qhullptest/qhullptest.cpp
+++ b/src/qhullptest/qhullptest.cpp
@@ -1,86 +1,86 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhullptest/qhullptest.cpp#1 $$Change: 1653 $
-** $DateTime: 2014/01/17 10:27:02 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhullptest/qhullptest.cpp#2 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include 
 #include 
 #include 
 #include "RoadTest.h"
 
 #include "../libqhullcpp/RoadError.h"
 
 using std::cout;
 using std::endl;
 
 namespace orgQhull {
 
 void addQhullTests(QStringList &args)
 {
     TESTadd_(add_QhullVertex_test); //copy
 
     if(args.contains("--all")){
         args.removeAll("--all");
         // up-to-date
         TESTadd_(add_Coordinates_test);
         TESTadd_(add_PointCoordinates_test);
         TESTadd_(add_QhullFacet_test);
         TESTadd_(add_QhullFacetList_test);
         TESTadd_(add_QhullFacetSet_test);
         TESTadd_(add_QhullHyperplane_test);
         TESTadd_(add_QhullLinkedList_test);
         TESTadd_(add_QhullPoint_test);
         TESTadd_(add_QhullPoints_test);
         TESTadd_(add_QhullPointSet_test);
         TESTadd_(add_QhullRidge_test);
         TESTadd_(add_QhullSet_test);
         TESTadd_(add_QhullVertex_test);
         TESTadd_(add_RboxPoints_test);
         TESTadd_(add_UsingLibQhull_test);
         // needs review
         // qhullStat
         TESTadd_(add_Qhull_test);
     }//--all
 }//addQhullTests
 
 int main(int argc, char *argv[])
 {
     QCoreApplication app(argc, argv);
     QStringList args= app.arguments();
     bool isAll= args.contains("--all");
     addQhullTests(args);
     int status=1010;
     try{
         status= RoadTest::runTests(args);
     }catch(const std::exception &e){
         cout << "FAIL!  : runTests() did not catch error\n";
         cout << e.what() << endl;
         if(!RoadError::emptyGlobalLog()){
             cout << RoadError::stringGlobalLog() << endl;
             RoadError::clearGlobalLog();
         }
     }
     if(!RoadError::emptyGlobalLog()){
         cout << RoadError::stringGlobalLog() << endl;
         RoadError::clearGlobalLog();
     }
     if(isAll){
         cout << "Finished test of libqhullcpp.  Test libqhull with eg/q_test" << endl;
     }else{
         cout << "Finished test of one class.  Test all classes with 'qhulltest --all'" << endl;
     }
     return status;
 }
 
 }//orgQhull
 
 int main(int argc, char *argv[])
 {
     return orgQhull::main(argc, argv); // Needs RoadTest:: for TESTadd_() linkage
 }
 
diff --git a/src/qhullr/unix_r.c b/src/qhullr/unix_r.c
index 83e4e6b..2eadbd5 100644
--- a/src/qhullr/unix_r.c
+++ b/src/qhullr/unix_r.c
@@ -1,366 +1,366 @@
 /*
  ---------------------------------
 
    unix.c
      command line interface to qhull
          includes SIOUX interface for Macintoshes
 
    see qh-qhull.htm
 
-   Copyright (c) 1993-2014 The Geometry Center.
-   $Id: //main/2011/qhull/src/qhullr/unix_r.c#4 $$Change: 1663 $
-   $DateTime: 2014/01/19 17:59:16 $$Author: bbarber $
+   Copyright (c) 1993-2015 The Geometry Center.
+   $Id: //main/2011/qhull/src/qhullr/unix_r.c#5 $$Change: 1810 $
+   $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include "mem_r.h"
 #include "qset_r.h"
 #include "libqhull_r.h"
 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 #if __cplusplus
 extern "C" {
   int isatty(int);
 }
 
 #elif _MSC_VER
 #include 
 #define isatty _isatty
 int _isatty(int);
 
 #else
 int isatty(int);  /* returns 1 if stdin is a tty
                    if "Undefined symbol" this can be deleted along with call in main() */
 #endif
 
 /*---------------------------------
 
   qh_prompt
     long prompt for qhull
 
   see:
     concise prompt below
 */
 char qh_prompta[]= "\n\
 qhull- compute convex hulls and related structures.\n\
     http://www.qhull.org  %s\n\
 \n\
 input (stdin):\n\
     first lines: dimension and number of points (or vice-versa).\n\
     other lines: point coordinates, best if one point per line\n\
     comments:    start with a non-numeric character\n\
     halfspaces:  use dim plus one and put offset after coefficients.\n\
                  May be preceeded by a single interior point ('H').\n\
 \n\
 options:\n\
     d    - Delaunay triangulation by lifting points to a paraboloid\n\
     d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
     v    - Voronoi diagram (dual of the Delaunay triangulation)\n\
     v Qu - furthest-site Voronoi diagram\n\
     Hn,n,... - halfspace intersection about point [n,n,0,...]\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Qc   - keep coplanar points with nearest facet\n\
     Qi   - keep interior points with nearest facet\n\
 \n\
 Qhull control options:\n\
     Qbk:n   - scale coord k so that low bound is n\n\
       QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
     QbB  - scale input to unit cube centered at the origin\n\
     Qbb  - scale last coordinate to [0,m] for Delaunay triangulations\n\
     Qbk:0Bk:0 - remove k-th coordinate from input\n\
     QJn  - randomly joggle input in range [-n,n]\n\
     QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
 %s%s%s%s";  /* split up qh_prompt for Visual C++ */
 char qh_promptb[]= "\
     Qf   - partition point to furthest outside facet\n\
     Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')\n\
     Qm   - only process points that would increase max_outside\n\
     Qr   - process random outside points instead of furthest ones\n\
     Qs   - search all points for the initial simplex\n\
     Qu   - for 'd' or 'v', compute upper hull without point at-infinity\n\
               returns furthest-site Delaunay triangulation\n\
     Qv   - test vertex neighbors for convexity\n\
     Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)\n\
     Qz   - add point-at-infinity to Delaunay triangulation\n\
     QGn  - good facet if visible from point n, -n for not visible\n\
     QVn  - good facet if it includes point n, -n if not\n\
     Q0   - turn off default premerge with 'C-0'/'Qx'\n\
     Q1     - sort merges by type instead of angle\n\
     Q2   - merge all non-convex at once instead of independent sets\n\
     Q3   - do not merge redundant vertices\n\
     Q4   - avoid old->new merges\n\
     Q5   - do not correct outer planes at end of qhull\n\
     Q6   - do not pre-merge concave or coplanar facets\n\
     Q7   - depth-first processing instead of breadth-first\n\
     Q8   - do not process near-inside points\n\
     Q9   - process furthest of furthest points\n\
     Q10  - no special processing for narrow distributions\n\
     Q11  - copy normals and recompute centrums for tricoplanar facets\n\
 \n\
 ";
 char qh_promptc[]= "\
 Topts- Trace options:\n\
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
     Ta   - annotate output with message codes\n\
     Tc   - check frequently during execution\n\
     Ts   - print statistics\n\
     Tv   - verify result: structure, convexity, and point inclusion\n\
     Tz   - send all output to stdout\n\
     TFn  - report summary when n or more facets created\n\
     TI file - input data from file, no spaces or single quotes\n\
     TO file - output results to file, may be enclosed in single quotes\n\
     TPn  - turn on tracing when point n added to hull\n\
      TMn - turn on tracing at merge n\n\
      TWn - trace merge facets when width > n\n\
     TRn  - rerun qhull n times.  Use with 'QJn'\n\
     TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
      TCn - stop qhull after building cone for point n (see TVn)\n\
 \n\
 Precision options:\n\
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
     En   - max roundoff error for distance computation\n\
     Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
     Vn   - min distance above plane for a visible facet (default 3C-n or En)\n\
     Un   - max distance below plane for a new, coplanar point (default Vn)\n\
     Wn   - min facet width for outside point (before roundoff, default 2Vn)\n\
 \n\
 Output formats (may be combined; if none, produces a summary to stdout):\n\
     f    - facet dump\n\
     G    - Geomview output (see below)\n\
     i    - vertices incident to each facet\n\
     m    - Mathematica output (2-d and 3-d)\n\
     o    - OFF format (dim, points and facets; Voronoi regions)\n\
     n    - normals with offsets\n\
     p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')\n\
     s    - summary (stderr)\n\
 \n\
 ";
 char qh_promptd[]= "\
 More formats:\n\
     Fa   - area for each facet\n\
     FA   - compute total area and volume for option 's'\n\
     Fc   - count plus coplanar points for each facet\n\
            use 'Qc' (default) for coplanar and 'Qi' for interior\n\
     FC   - centrum or Voronoi center for each facet\n\
     Fd   - use cdd format for input (homogeneous with offset first)\n\
     FD   - use cdd format for numeric output (offset first)\n\
     FF   - facet dump without ridges\n\
     Fi   - inner plane for each facet\n\
            for 'v', separating hyperplanes for bounded Voronoi regions\n\
     FI   - ID of each facet\n\
     Fm   - merge count for each facet (511 max)\n\
     FM   - Maple output (2-d and 3-d)\n\
     Fn   - count plus neighboring facets for each facet\n\
     FN   - count plus neighboring facets for each point\n\
     Fo   - outer plane (or max_outside) for each facet\n\
            for 'v', separating hyperplanes for unbounded Voronoi regions\n\
     FO   - options and precision constants\n\
     Fp   - dim, count, and intersection coordinates (halfspace only)\n\
     FP   - nearest vertex and distance for each coplanar point\n\
     FQ   - command used for qhull\n\
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                       output: #vertices, #facets, #coplanars, #nonsimplicial\n\
                     #real (2), max outer plane, min vertex\n\
     FS   - sizes:   #int (0)\n\
                     #real (2) tot area, tot volume\n\
     Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
     Fv   - count plus vertices for each facet\n\
            for 'v', Voronoi diagram as Voronoi vertices for pairs of sites\n\
     FV   - average of vertices (a feasible point for 'H')\n\
     Fx   - extreme points (in order for 2-d)\n\
 \n\
 ";
 char qh_prompte[]= "\
 Geomview options (2-d, 3-d, and 4-d; 2-d Voronoi)\n\
     Ga   - all points as dots\n\
      Gp  -  coplanar points and vertices as radii\n\
      Gv  -  vertices as spheres\n\
     Gi   - inner planes only\n\
      Gn  -  no planes\n\
      Go  -  outer planes only\n\
     Gc   - centrums\n\
     Gh   - hyperplane intersections\n\
     Gr   - ridges\n\
     GDn  - drop dimension n in 3-d and 4-d output\n\
     Gt   - for 3-d 'd', transparent outer ridges\n\
 \n\
 Print options:\n\
     PAn  - keep n largest facets by area\n\
     Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
     PDk:n - drop facet if normal[k] >= n\n\
     Pg   - print good facets (needs 'QGn' or 'QVn')\n\
     PFn  - keep facets whose area is at least n\n\
     PG   - print neighbors of good facets\n\
     PMn  - keep n facets with most merges\n\
     Po   - force output.  If error, output neighborhood of facet\n\
     Pp   - do not report precision problems\n\
 \n\
     .    - list of all options\n\
     -    - one line descriptions of all options\n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt2
     synopsis for qhull
 */
 char qh_prompt2[]= "\n\
 qhull- compute convex hulls and related structures.  Qhull %s\n\
     input (stdin): dimension, n, point coordinates\n\
     comments start with a non-numeric character\n\
     halfspace: use dim+1 and put offsets after coefficients\n\
 \n\
 options (qh-quick.htm):\n\
     d    - Delaunay triangulation by lifting points to a paraboloid\n\
     d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
     v    - Voronoi diagram as the dual of the Delaunay triangulation\n\
     v Qu - furthest-site Voronoi diagram\n\
     H1,1 - Halfspace intersection about [1,1,0,...] via polar duality\n\
     Qt   - triangulated output\n\
     QJ   - joggled input instead of merged facets\n\
     Tv   - verify result: structure, convexity, and point inclusion\n\
     .    - concise list of all options\n\
     -    - one-line description of each option\n\
 \n\
 Output options (subset):\n\
     s    - summary of results (default)\n\
     i    - vertices incident to each facet\n\
     n    - normals with offsets\n\
     p    - vertex coordinates (if 'Qc', includes coplanar points)\n\
            if 'v', Voronoi vertices\n\
     Fp   - halfspace intersections\n\
     Fx   - extreme points (convex hull vertices)\n\
     FA   - compute total area and volume\n\
     o    - OFF format (if 'v', outputs Voronoi regions)\n\
     G    - Geomview output (2-d, 3-d and 4-d)\n\
     m    - Mathematica output (2-d and 3-d)\n\
     QVn  - print facets that include point n, -n if not\n\
     TO file- output results to file, may be enclosed in single quotes\n\
 \n\
 examples:\n\
     rbox c d D2 | qhull Qc s f Fx | more      rbox 1000 s | qhull Tv s FA\n\
     rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v Qbb Qt p\n\
     rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o\n\
     rbox c | qhull n                          rbox c | qhull FV n | qhull H Fp\n\
     rbox d D12 | qhull QR0 FA                 rbox c D7 | qhull FA TF1000\n\
     rbox y 1000 W0 | qhull                    rbox 10 | qhull v QJ o Fv\n\
 \n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt3
     concise prompt for qhull
 */
 char qh_prompt3[]= "\n\
 Qhull %s.\n\
 Except for 'F.' and 'PG', upper-case options take an argument.\n\
 \n\
  delaunay       voronoi        Geomview       Halfspace      facet_dump\n\
  incidences     mathematica    normals        OFF_format     points\n\
  summary\n\
 \n\
  Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
  FD-cdd-out     FF-dump-xridge Finner         FIDs           Fmerges\n\
  Fneighbors     FNeigh-vertex  Fouter         FOptions       Fpoint-intersect\n\
  FPoint_near    FQhull         Fsummary       FSize          Ftriangles\n\
  Fvertices      Fvoronoi       FVertex-ave    Fxtremes       FMaple\n\
 \n\
  Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
  Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
  Gtransparent\n\
 \n\
  PArea-keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
  PGood_neighbors PMerge-keep   Poutput_forced Pprecision_not\n\
 \n\
  QbBound 0:0.5  Qbk:0Bk:0_drop QbB-scale-box  Qbb-scale-last Qcoplanar\n\
  Qfurthest      Qgood_only     QGood_point    Qinterior      Qmax_out\n\
  QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
  QupperDelaunay QVertex_good   Qvneighbors    Qxact_merge    Qzinfinite\n\
 \n\
  Q0_no_premerge Q1_no_angle    Q2_no_independ Q3_no_redundant Q4_no_old\n\
  Q5_no_check_out Q6_no_concave Q7_depth_first Q8_no_near_in  Q9_pick_furthest\n\
  Q10_no_narrow  Q11_trinormals\n\
 \n\
  T4_trace       Tannotate      Tcheck_often   Tstatistics    Tverify\n\
  Tz_stdout      TFacet_log     TInput_file    TPoint_trace   TMerge_trace\n\
  TOutput_file   TRerun         TWide_trace    TVertex_stop   TCone_stop\n\
 \n\
  Angle_max      Centrum_size   Error_round    Random_dist    Visible_min\n\
  Ucoplanar_max  Wide_outside\n\
 ";
 
 /*---------------------------------
 
   main( argc, argv )
     processes the command line, calls qhull() to do the work, and exits
 
   design:
     initializes data structures
     reads points
     finishes initialization
     computes convex hull and other structures
     checks the result
     writes the output
     frees memory
 */
 int main(int argc, char *argv[]) {
   int curlong, totlong; /* used !qh_NOmem */
   int exitcode, numpoints, dim;
   coordT *points;
   boolT ismalloc;
   qhT qh_qh;
   qhT *qh= &qh_qh;
 
   if ((argc == 1) && isatty( 0 /*stdin*/)) {
     fprintf(stdout, qh_prompt2, qh_version);
     exit(qh_ERRnone);
   }
   if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompta, qh_version, qh_DEFAULTbox,
                 qh_promptb, qh_promptc, qh_promptd, qh_prompte);
     exit(qh_ERRnone);
   }
   if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompt3, qh_version);
     exit(qh_ERRnone);
   }
   qh_init_A(qh, stdin, stdout, stderr, argc, argv);  /* sets qh->qhull_command */
   exitcode= setjmp(qh->errexit); /* simple statement for CRAY J916 */
   if (!exitcode) {
     qh_initflags(qh, qh->qhull_command);
     points= qh_readpoints(qh, &numpoints, &dim, &ismalloc);
     qh_init_B(qh, points, numpoints, dim, ismalloc);
     qh_qhull(qh);
     qh_check_output(qh);
     qh_produce_output(qh);
     if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPpoint && !qh->STOPcone)
       qh_check_points(qh);
     exitcode= qh_ERRnone;
   }
   qh->NOerrexit= True;  /* no more setjmp */
 #ifdef qh_NOmem
   qh_freeqhull(qh, True);
 #else
   qh_freeqhull(qh, False);
   qh_memfreeshort(qh, &curlong, &totlong);
   if (curlong || totlong)
     fprintf(stderr, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
        totlong, curlong);
 #endif
   return exitcode;
 } /* main */
 
diff --git a/src/qhulltest/Coordinates_test.cpp b/src/qhulltest/Coordinates_test.cpp
index 55df313..d771bf8 100644
--- a/src/qhulltest/Coordinates_test.cpp
+++ b/src/qhulltest/Coordinates_test.cpp
@@ -1,534 +1,534 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/Coordinates_test.cpp#4 $$Change: 1490 $
-** $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/Coordinates_test.cpp#6 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "Coordinates.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class Coordinates_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void t_construct();
     void t_convert();
     void t_element();
     void t_readonly();
     void t_operator();
     void t_const_iterator();
     void t_iterator();
     void t_coord_iterator();
     void t_mutable_coord_iterator();
     void t_readwrite();
     void t_search();
     void t_io();
 };//Coordinates_test
 
 void
 add_Coordinates_test()
 {
     new Coordinates_test();
 }
 
 void Coordinates_test::
 t_construct()
 {
     Coordinates c;
     QCOMPARE(c.size(), 0U);
     QVERIFY(c.isEmpty());
     c << 1.0;
     QCOMPARE(c.count(), 1);
     Coordinates c2(c);
     c2 << 2.0;
     QCOMPARE(c2.count(), 2);
     Coordinates c3;
     c3 = c2;
     QCOMPARE(c3.count(), 2);
     QCOMPARE(c3[0]+c3[1], 3.0);
     QVERIFY(c2==c3);
     std::vector vc;
     vc.push_back(3.0);
     vc.push_back(4.0);
     Coordinates c4(vc);
     QCOMPARE(c4[0]+c4[1], 7.0);
     Coordinates c5(c3);
     QVERIFY(c5==c3);
     c5= vc;
     QVERIFY(c5!=c3);
     QVERIFY(c5==c4);
 }//t_construct
 
 void Coordinates_test::
 t_convert()
 {
     Coordinates c;
     c << 1.0 << 3.0;
     QCOMPARE(c.data()[1], 3.0);
     coordT *c2= c.data();
     const coordT *c3= c.data();
     QCOMPARE(c2, c3);
     std::vector vc= c.toStdVector();
     QCOMPARE(vc.size(), c.size());
     for(size_t k= vc.size(); k--; ){
         QCOMPARE(vc[k], c[k]);
     }
     QList qc= c.toQList();
     QCOMPARE(qc.count(), c.count());
     for(int k= qc.count(); k--; ){
         QCOMPARE(qc[k], c[k]);
     }
     Coordinates c4;
     c4= std::vector(2, 0.0);
     QCOMPARE(c4.back(), 0.0);
     Coordinates c5(std::vector(2, 0.0));
     QCOMPARE(c4.size(), c5.size());
     QVERIFY(c4==c5);
 }//t_convert
 
 void Coordinates_test::
 t_element()
 {
     Coordinates c;
     c << 1.0 << -2.0;
     c.at(1)= -3;
     QCOMPARE(c.at(1), -3.0);
     QCOMPARE(c.back(), -3.0);
     QCOMPARE(c.front(), 1.0);
     c[1]= -2.0;
     QCOMPARE(c[1],-2.0);
     QCOMPARE(c.first(), 1.0);
     c.first()= 2.0;
     QCOMPARE(c.first(), 2.0);
     QCOMPARE(c.last(), -2.0);
     c.last()= 0.0;
     QCOMPARE(c.first()+c.last(), 2.0);
     coordT *c4= &c.first();
     const coordT *c5= &c.first();
     QCOMPARE(c4, c5);
     coordT *c6= &c.last();
     const coordT *c7= &c.last();
     QCOMPARE(c6, c7);
     Coordinates c2= c.mid(1);
     QCOMPARE(c2.count(), 1);
     c << 3.0;
     Coordinates c3= c.mid(1,1);
     QCOMPARE(c2, c3);
     QCOMPARE(c3.value(-1, -1.0), -1.0);
     QCOMPARE(c3.value(3, 4.0), 4.0);
     QCOMPARE(c.value(2, 4.0), 3.0);
 }//t_element
 
 void Coordinates_test::
 t_readonly()
 {
     Coordinates c;
     QCOMPARE(c.size(), 0u);
     QCOMPARE(c.count(), 0);
     QVERIFY(c.empty());
     QVERIFY(c.isEmpty());
     c << 1.0 << -2.0;
     QCOMPARE(c.size(), 2u);
     QCOMPARE(c.count(), 2);
     QVERIFY(!c.empty());
     QVERIFY(!c.isEmpty());
 }//t_readonly
 
 void Coordinates_test::
 t_operator()
 {
     Coordinates c;
     Coordinates c2(c);
     QVERIFY(c==c2);
     QVERIFY(!(c!=c2));
     c << 1.0;
     QVERIFY(!(c==c2));
     QVERIFY(c!=c2);
     c2 << 1.0;
     QVERIFY(c==c2);
     QVERIFY(!(c!=c2));
     c[0]= 0.0;
     QVERIFY(c!=c2);
     Coordinates c3= c+c2;
     QCOMPARE(c3.count(), 2);
     QCOMPARE(c3[0], 0.0);
     QCOMPARE(c3[1], 1.0);
     c3 += c3;
     QCOMPARE(c3.count(), 4);
     QCOMPARE(c3[2], 0.0);
     QCOMPARE(c3[3], 1.0);
     c3 += c2;
     QCOMPARE(c3[4], 1.0);
     c3 += 5.0;
     QCOMPARE(c3.count(), 6);
     QCOMPARE(c3[5], 5.0);
     // << checked above
 }//t_operator
 
 void Coordinates_test::
 t_const_iterator()
 {
     Coordinates c;
     QCOMPARE(c.begin(), c.end());
     // begin and end checked elsewhere
     c << 1.0 << 3.0;
     Coordinates::const_iterator i= c.begin();
     QCOMPARE(*i, 1.0);
     QCOMPARE(i[1], 3.0);
     // i[1]= -3.0; // compiler error
     // operator-> is not applicable to double
     QCOMPARE(*i++, 1.0);
     QCOMPARE(*i, 3.0);
     QCOMPARE(*i--, 3.0);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 3.0);
     QCOMPARE(*++i, 3.0);
     QCOMPARE(*(i-1), 1.0);
     QCOMPARE(*--i, 1.0);
     QVERIFY(i==c.begin());
     QVERIFY(i==c.constBegin());
     QVERIFY(i!=c.end());
     QVERIFY(i!=c.constEnd());
     QVERIFY(i=c.begin());
     QVERIFY(i+1<=c.end());
     QVERIFY(i+1>c.begin());
     Coordinates::iterator i2= c.begin();
     Coordinates::const_iterator i3(i2);
     QCOMPARE(*i3, 1.0);
     QCOMPARE(i3[1], 3.0);
 }//t_const_iterator
 
 void Coordinates_test::
 t_iterator()
 {
     Coordinates c;
     QCOMPARE(c.begin(), c.end());
     // begin and end checked elsewhere
     c << 1.0 << 3.0;
     Coordinates::iterator i= c.begin();
     QCOMPARE(*i, 1.0);
     QCOMPARE(i[1], 3.0);
     *i= -1.0;
     QCOMPARE(*i, -1.0);
     i[1]= -3.0;
     QCOMPARE(i[1], -3.0);
     *i= 1.0;
     // operator-> is not applicable to double
     QCOMPARE(*i++, 1.0);
     QCOMPARE(*i, -3.0);
     *i= 3.0;
     QCOMPARE(*i--, 3.0);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 3.0);
     QCOMPARE(*++i, 3.0);
     QCOMPARE(*(i-1), 1.0);
     QCOMPARE(*--i, 1.0);
     QVERIFY(i==c.begin());
     QVERIFY(i==c.constBegin());
     QVERIFY(i!=c.end());
     QVERIFY(i!=c.constEnd());
     QVERIFY(i=c.begin());
     QVERIFY(i+1<=c.end());
     QVERIFY(i+1>c.begin());
 }//t_iterator
 
 void Coordinates_test::
 t_coord_iterator()
 {
     Coordinates c;
     c << 1.0 << 3.0;
     CoordinatesIterator i(c);
     CoordinatesIterator i2= c;
     QVERIFY(i.findNext(1.0));
     QVERIFY(!i.findNext(2.0));
     QVERIFY(!i.findNext(3.0));
     QVERIFY(i.findPrevious(3.0));
     QVERIFY(!i.findPrevious(2.0));
     QVERIFY(!i.findPrevious(1.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(3.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(1.0));
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     Coordinates c2;
     i2= c2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekPrevious(), 3.0);
     QCOMPARE(i.previous(), 3.0);
     QCOMPARE(i.previous(), 1.0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), 1.0);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), 1.0);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.next(), 3.0);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), 1.0);
 }//t_coord_iterator
 
 void Coordinates_test::
 t_mutable_coord_iterator()
 {
     // Same tests as CoordinatesIterator
     Coordinates c;
     c << 1.0 << 3.0;
     MutableCoordinatesIterator i(c);
     MutableCoordinatesIterator i2= c;
     QVERIFY(i.findNext(1.0));
     QVERIFY(!i.findNext(2.0));
     QVERIFY(!i.findNext(3.0));
     QVERIFY(i.findPrevious(3.0));
     QVERIFY(!i.findPrevious(2.0));
     QVERIFY(!i.findPrevious(1.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(3.0));
     QVERIFY(i2.findNext(3.0));
     QVERIFY(i2.findPrevious(1.0));
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     Coordinates c2;
     i2= c2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekPrevious(), 3.0);
     QCOMPARE(i.peekPrevious(), 3.0);
     QCOMPARE(i.previous(), 3.0);
     QCOMPARE(i.previous(), 1.0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), 1.0);
     QCOMPARE(i.next(), 1.0);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.next(), 3.0);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), 1.0);
 
     // Mutable tests
     i.toFront();
     i.peekNext()= -1.0;
     QCOMPARE(i.peekNext(), -1.0);
     QCOMPARE((i.next()= 1.0), 1.0);
     QCOMPARE(i.peekPrevious(), 1.0);
     i.remove();
     QCOMPARE(c.count(), 1);
     i.remove();
     QCOMPARE(c.count(), 1);
     QCOMPARE(i.peekNext(), 3.0);
     i.insert(1.0);
     i.insert(2.0);
     QCOMPARE(c.count(), 3);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.peekPrevious(), 2.0);
     i.peekPrevious()= -2.0;
     QCOMPARE(i.peekPrevious(), -2.0);
     QCOMPARE((i.previous()= 2.0), 2.0);
     QCOMPARE(i.peekNext(), 2.0);
     i.toBack();
     i.remove();
     QCOMPARE(c.count(), 3); // unchanged
     i.toFront();
     i.remove();
     QCOMPARE(c.count(), 3); // unchanged
     QCOMPARE(i.peekNext(), 1.0);
     i.remove();
     QCOMPARE(c.count(), 3); // unchanged
     i.insert(0.0);
     QCOMPARE(c.count(), 4);
     QCOMPARE(i.value(), 0.0);
     QCOMPARE(i.peekPrevious(), 0.0);
     i.setValue(-10.0);
     QCOMPARE(c.count(), 4); // unchanged
     QCOMPARE(i.peekNext(), 1.0);
     QCOMPARE(i.peekPrevious(), -10.0);
     i.findNext(1.0);
     i.setValue(-1.0);
     QCOMPARE(i.peekPrevious(), -1.0);
     i.setValue(1.0);
     QCOMPARE(i.peekPrevious(), 1.0);
     QCOMPARE(i.value(), 1.0);
     i.findPrevious(1.0);
     i.setValue(-1.0);
     QCOMPARE(i.peekNext(), -1.0);
     i.toBack();
     QCOMPARE(i.previous(), 3.0);
     i.setValue(-3.0);
     QCOMPARE(i.peekNext(), -3.0);
     double d= i.value();
     QCOMPARE(d, -3.0);
     QCOMPARE(i.previous(), 2.0);
 }//t_mutable_coord_iterator
 
 void Coordinates_test::
 t_readwrite()
 {
     Coordinates c;
     c.clear();
     QCOMPARE(c.count(), 0);
     c << 1.0 << 3.0;
     c.clear();
     QCOMPARE(c.count(), 0);
     c << 1.0 << 3.0;
     c.erase(c.begin(), c.end());
     QCOMPARE(c.count(), 0);
     c << 1.0 << 0.0;
     Coordinates::iterator i= c.erase(c.begin());
     QCOMPARE(*i, 0.0);
     i= c.insert(c.end(), 1.0);
     QCOMPARE(*i, 1.0);
     QCOMPARE(c.count(), 2);
     c.pop_back();
     QCOMPARE(c.count(), 1);   // 0
     QCOMPARE(c[0], 0.0);
     c.push_back(2.0);
     QCOMPARE(c.count(), 2);
     c.append(3.0);
     QCOMPARE(c.count(), 3);   // 0, 2, 3
     QCOMPARE(c[2], 3.0);
     c.insert(0, 4.0);
     QCOMPARE(c[0], 4.0);
     QCOMPARE(c[3], 3.0);
     c.insert(c.count(), 5.0);
     QCOMPARE(c.count(), 5);   // 4, 0, 2, 3, 5
     QCOMPARE(c[4], 5.0);
     c.move(4, 0);
     QCOMPARE(c.count(), 5);   // 5, 4, 0, 2, 3
     QCOMPARE(c[0], 5.0);
     c.pop_front();
     QCOMPARE(c.count(), 4);
     QCOMPARE(c[0], 4.0);
     c.prepend(6.0);
     QCOMPARE(c.count(), 5);   // 6, 4, 0, 2, 3
     QCOMPARE(c[0], 6.0);
     c.push_front(7.0);
     QCOMPARE(c.count(), 6);
     QCOMPARE(c[0], 7.0);
     c.removeAt(1);
     QCOMPARE(c.count(), 5);   // 7, 4, 0, 2, 3
     QCOMPARE(c[1], 4.0);
     c.removeFirst();
     QCOMPARE(c.count(), 4);   // 4, 0, 2, 3
     QCOMPARE(c[0], 4.0);
     c.removeLast();
     QCOMPARE(c.count(), 3);
     QCOMPARE(c.last(), 2.0);
     c.replace(2, 8.0);
     QCOMPARE(c.count(), 3);   // 4, 0, 8
     QCOMPARE(c[2], 8.0);
     c.swap(0, 2);
     QCOMPARE(c[2], 4.0);
     double d= c.takeAt(2);
     QCOMPARE(c.count(), 2);   // 8, 0
     QCOMPARE(d, 4.0);
     double d2= c.takeFirst();
     QCOMPARE(c.count(), 1);   // 0
     QCOMPARE(d2, 8.0);
     double d3= c.takeLast();
     QVERIFY(c.isEmpty()); \
     QCOMPARE(d3, 0.0);
 }//t_readwrite
 
 void Coordinates_test::
 t_search()
 {
     Coordinates c;
     c << 1.0 << 3.0 << 1.0;
     QVERIFY(c.contains(1.0));
     QVERIFY(c.contains(3.0));
     QVERIFY(!c.contains(0.0));
     QCOMPARE(c.count(1.0), 2);
     QCOMPARE(c.count(3.0), 1);
     QCOMPARE(c.count(0.0), 0);
     QCOMPARE(c.indexOf(1.0), 0);
     QCOMPARE(c.indexOf(3.0), 1);
     QCOMPARE(c.indexOf(1.0, -1), 2);
     QCOMPARE(c.indexOf(3.0, -1), -1);
     QCOMPARE(c.indexOf(3.0, -2), 1);
     QCOMPARE(c.indexOf(1.0, -3), 0);
     QCOMPARE(c.indexOf(1.0, -4), 0);
     QCOMPARE(c.indexOf(1.0, 1), 2);
     QCOMPARE(c.indexOf(3.0, 2), -1);
     QCOMPARE(c.indexOf(1.0, 2), 2);
     QCOMPARE(c.indexOf(1.0, 3), -1);
     QCOMPARE(c.indexOf(1.0, 4), -1);
     QCOMPARE(c.lastIndexOf(1.0), 2);
     QCOMPARE(c.lastIndexOf(3.0), 1);
     QCOMPARE(c.lastIndexOf(1.0, -1), 2);
     QCOMPARE(c.lastIndexOf(3.0, -1), 1);
     QCOMPARE(c.lastIndexOf(3.0, -2), 1);
     QCOMPARE(c.lastIndexOf(1.0, -3), 0);
     QCOMPARE(c.lastIndexOf(1.0, -4), -1);
     QCOMPARE(c.lastIndexOf(1.0, 1), 0);
     QCOMPARE(c.lastIndexOf(3.0, 2), 1);
     QCOMPARE(c.lastIndexOf(1.0, 2), 2);
     QCOMPARE(c.lastIndexOf(1.0, 3), 2);
     QCOMPARE(c.lastIndexOf(1.0, 4), 2);
     c.removeAll(3.0);
     QCOMPARE(c.count(), 2);
     c.removeAll(4.0);
     QCOMPARE(c.count(), 2);
     c.removeAll(1.0);
     QCOMPARE(c.count(), 0);
     c.removeAll(4.0);
     QCOMPARE(c.count(), 0);
 }//t_search
 
 void Coordinates_test::
 t_io()
 {
     Coordinates c;
     c << 1.0 << 2.0 << 3.0;
     ostringstream os;
     os << "Coordinates 1-2-3\n" << c;
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("2"), 2);
 }//t_io
 
 }//orgQhull
 
 #include "moc/Coordinates_test.moc"
diff --git a/src/qhulltest/PointCoordinates_test.cpp b/src/qhulltest/PointCoordinates_test.cpp
index 608a9fb..14a4268 100644
--- a/src/qhulltest/PointCoordinates_test.cpp
+++ b/src/qhulltest/PointCoordinates_test.cpp
@@ -1,396 +1,478 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/PointCoordinates_test.cpp#8 $$Change: 1708 $
-** $DateTime: 2014/03/26 19:13:56 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/PointCoordinates_test.cpp#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "PointCoordinates.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 using std::stringstream;
 
 namespace orgQhull {
 
 class PointCoordinates_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
-    void t_construct();
+    void t_construct_q();
+    void t_construct_qh();
     void t_convert();
     void t_getset();
     void t_element();
     void t_foreach();
     void t_search();
     void t_modify();
     void t_append_points();
     void t_coord_iterator();
     void t_io();
 };//PointCoordinates_test
 
 void
 add_PointCoordinates_test()
 {
     new PointCoordinates_test();
 }
 
 void PointCoordinates_test::
-t_construct()
+t_construct_q()
 {
-    PointCoordinates pc;
+    Qhull q;
+    PointCoordinates pc(q);
     QCOMPARE(pc.size(), 0U);
     QCOMPARE(pc.coordinateCount(), 0);
     QCOMPARE(pc.dimension(), 0);
     QCOMPARE(pc.coordinates(), (coordT *)0);
     QVERIFY(pc.isEmpty());
     pc.checkValid();
-    PointCoordinates pc7(2);
+    PointCoordinates pc7(q, 2);
     QCOMPARE(pc7.dimension(), 2);
     QCOMPARE(pc7.count(), 0);
     QVERIFY(pc7.isEmpty());
     QVERIFY(pc7.comment().empty());
     pc7.checkValid();
-    PointCoordinates pc2("Test pc2");
+    PointCoordinates pc2(q, "Test pc2");
     QCOMPARE(pc2.count(), 0);
     QVERIFY(pc2.isEmpty());
     QCOMPARE(pc2.comment(), std::string("Test pc2"));
     pc2.checkValid();
-    PointCoordinates pc3(3, "Test 3-d pc3");
+    PointCoordinates pc3(q, 3, "Test 3-d pc3");
     QCOMPARE(pc3.dimension(), 3);
     QVERIFY(pc3.isEmpty());
     pc3.checkValid();
     coordT c[]= { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };
-    PointCoordinates pc4(2, "Test 2-d pc4", 6, c);
+    PointCoordinates pc4(q, 2, "Test 2-d pc4", 6, c);
     QCOMPARE(pc4.dimension(), 2);
     QCOMPARE(pc4.count(), 3);
     QCOMPARE(pc4.size(), 3u);
     QVERIFY(!pc4.isEmpty());
     pc4.checkValid();
     QhullPoint p= pc4[2];
     QCOMPARE(p[1], 5.0);
     // QhullPoint refers to PointCoordinates
     p[1] += 1.0;
     QCOMPARE(pc4[2][1], 6.0);
-    PointCoordinates pc5(4, "Test 4-d pc5 with insufficient coordinates", 6, c);
+    PointCoordinates pc5(q, 4, "Test 4-d pc5 with insufficient coordinates", 6, c);
     QCOMPARE(pc5.dimension(), 4);
     QCOMPARE(pc5.count(), 1);
     QCOMPARE(pc5.extraCoordinatesCount(), 2);
     QCOMPARE(pc5.extraCoordinates()[1], 5.0);
     QVERIFY(!pc5.isEmpty());;
     std::vector vc;
     vc.push_back(3.0);
     vc.push_back(4.0);
     vc.push_back(5.0);
     vc.push_back(6.0);
     vc.push_back(7.0);
     vc.push_back(9.0);
     pc5.append(2, &vc[3]); // Copy of vc[]
     pc5.checkValid();
-    QhullPoint p5(4, &vc[1]);
+    QhullPoint p5(q, 4, &vc[1]);
     QCOMPARE(pc5[1], p5);
     PointCoordinates pc6(pc5); // Makes copy of point_coordinates
     QCOMPARE(pc6[1], p5);
     QVERIFY(pc6==pc5);
     QhullPoint p6= pc5[1];  // Refers to pc5.coordinates
     pc5[1][0] += 1.0;
     QCOMPARE(pc5[1], p6);
     QVERIFY(pc5[1]!=p5);
     QVERIFY(pc6!=pc5);
     pc6= pc5;
     QVERIFY(pc6==pc5);
-    PointCoordinates pc8;
+    PointCoordinates pc8(q);
     pc6= pc8;
     QVERIFY(pc6!=pc5);
     QVERIFY(pc6.isEmpty());
-}//t_construct
+}//t_construct_q
+
+void PointCoordinates_test::
+t_construct_qh()
+{
+    QhullQh qh;
+    PointCoordinates pc(qh);
+    QCOMPARE(pc.size(), 0U);
+    QCOMPARE(pc.coordinateCount(), 0);
+    QCOMPARE(pc.dimension(), 0);
+    QCOMPARE(pc.coordinates(), (coordT *)0);
+    QVERIFY(pc.isEmpty());
+    pc.checkValid();
+    PointCoordinates pc7(qh, 2);
+    QCOMPARE(pc7.dimension(), 2);
+    QCOMPARE(pc7.count(), 0);
+    QVERIFY(pc7.isEmpty());
+    QVERIFY(pc7.comment().empty());
+    pc7.checkValid();
+    PointCoordinates pc2(qh, "Test pc2");
+    QCOMPARE(pc2.count(), 0);
+    QVERIFY(pc2.isEmpty());
+    QCOMPARE(pc2.comment(), std::string("Test pc2"));
+    pc2.checkValid();
+    PointCoordinates pc3(qh, 3, "Test 3-d pc3");
+    QCOMPARE(pc3.dimension(), 3);
+    QVERIFY(pc3.isEmpty());
+    pc3.checkValid();
+    coordT c[]= { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };
+    PointCoordinates pc4(qh, 2, "Test 2-d pc4", 6, c);
+    QCOMPARE(pc4.dimension(), 2);
+    QCOMPARE(pc4.count(), 3);
+    QCOMPARE(pc4.size(), 3u);
+    QVERIFY(!pc4.isEmpty());
+    pc4.checkValid();
+    QhullPoint p= pc4[2];
+    QCOMPARE(p[1], 5.0);
+    // QhullPoint refers to PointCoordinates
+    p[1] += 1.0;
+    QCOMPARE(pc4[2][1], 6.0);
+    PointCoordinates pc5(qh, 4, "Test 4-d pc5 with insufficient coordinates", 6, c);
+    QCOMPARE(pc5.dimension(), 4);
+    QCOMPARE(pc5.count(), 1);
+    QCOMPARE(pc5.extraCoordinatesCount(), 2);
+    QCOMPARE(pc5.extraCoordinates()[1], 5.0);
+    QVERIFY(!pc5.isEmpty());;
+    std::vector vc;
+    vc.push_back(3.0);
+    vc.push_back(4.0);
+    vc.push_back(5.0);
+    vc.push_back(6.0);
+    vc.push_back(7.0);
+    vc.push_back(9.0);
+    pc5.append(2, &vc[3]); // Copy of vc[]
+    pc5.checkValid();
+    QhullPoint p5(qh, 4, &vc[1]);
+    QCOMPARE(pc5[1], p5);
+    PointCoordinates pc6(pc5); // Makes copy of point_coordinates
+    QCOMPARE(pc6[1], p5);
+    QVERIFY(pc6==pc5);
+    QhullPoint p6= pc5[1];  // Refers to pc5.coordinates
+    pc5[1][0] += 1.0;
+    QCOMPARE(pc5[1], p6);
+    QVERIFY(pc5[1]!=p5);
+    QVERIFY(pc6!=pc5);
+    pc6= pc5;
+    QVERIFY(pc6==pc5);
+    PointCoordinates pc8(qh);
+    pc6= pc8;
+    QVERIFY(pc6!=pc5);
+    QVERIFY(pc6.isEmpty());
+}//t_construct_qh
 
 void PointCoordinates_test::
 t_convert()
 {
+    Qhull q;
     //defineAs tested above
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
-    PointCoordinates ps(3, "two 3-d points", 6, c);
+    PointCoordinates ps(q, 3, "two 3-d points", 6, c);
     QCOMPARE(ps.dimension(), 3);
     QCOMPARE(ps.size(), 2u);
     const coordT *c2= ps.constData();
     QVERIFY(c!=c2);
     QCOMPARE(c[0], c2[0]);
     const coordT *c3= ps.data();
     QCOMPARE(c3, c2);
     coordT *c4= ps.data();
     QCOMPARE(c4, c2);
     std::vector vs= ps.toStdVector();
     QCOMPARE(vs.size(), 6u);
     QCOMPARE(vs[5], 5.0);
     QList qs= ps.toQList();
     QCOMPARE(qs.size(), 6);
     QCOMPARE(qs[5], 5.0);
 }//t_convert
 
 void PointCoordinates_test::
 t_getset()
 {
     // See t_construct() for test of coordinates, coordinateCount, dimension, empty, isEmpty, ==, !=
     // See t_construct() for test of checkValid, comment, setDimension
-    PointCoordinates pc("Coordinates c");
+    Qhull q;
+    PointCoordinates pc(q, "Coordinates c");
     pc.setComment("New comment");
     QCOMPARE(pc.comment(), std::string("New comment"));
     pc.checkValid();
     pc.makeValid();  // A no-op
     pc.checkValid();
     Coordinates cs= pc.getCoordinates();
     QVERIFY(cs.isEmpty());
     PointCoordinates pc2(pc);
     pc.setDimension(3);
     QVERIFY(pc2!=pc);
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     pc.append(6, c);
     pc.checkValid();
     pc.makeValid();  // A no-op
     QhullPoint p= pc[0];
     QCOMPARE(p[2], 2.0);
     try{
         pc.setDimension(2);
         QFAIL("setDimension(2) did not fail for 3-d.");
     }catch (const std::exception &e) {
         const char *s= e.what();
         cout << "INFO   : Caught " << s;
     }
 }//t_getset
 
 void PointCoordinates_test::
 t_element()
 {
+    Qhull q;
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
-    PointCoordinates pc(2, "2-d points", 6, c);
+    PointCoordinates pc(q, 2, "2-d points", 6, c);
     QhullPoint p= pc.at(0);
     QCOMPARE(p, pc[0]);
     QCOMPARE(p, pc.first());
     QCOMPARE(p, pc.value(0));
     p= pc.back();
     QCOMPARE(p, pc[2]);
     QCOMPARE(p, pc.last());
     QCOMPARE(p, pc.value(2));
     QhullPoints ps= pc.mid(1, 2);
     QCOMPARE(ps[1], p);
 }//t_element
 
 void PointCoordinates_test::
 t_foreach()
 {
+    Qhull q;
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
-    PointCoordinates pc(2, "2-d points", 6, c);
+    PointCoordinates pc(q, 2, "2-d points", 6, c);
     QhullPoints::Iterator i= pc.begin();
     QhullPoint p= pc[0];
     QCOMPARE(*i, p);
     QCOMPARE((*i)[0], 0.0);
     QhullPoint p3= pc[2];
     i= pc.end();
     QCOMPARE(i[-1], p3);
-    const PointCoordinates pc2(2, "2-d points", 6, c);
+    const PointCoordinates pc2(q, 2, "2-d points", 6, c);
     QhullPoints::ConstIterator i2= pc.begin();
     const QhullPoint p0= pc2[0];
     QCOMPARE(*i2, p0);
     QCOMPARE((*i2)[0], 0.0);
     QhullPoints::ConstIterator i3= i2;
     QCOMPARE(i3, i2);
     QCOMPARE((*i3)[0], 0.0);
     i3= pc.constEnd();
     --i3;
     QhullPoint p2= pc2[2];
     QCOMPARE(*i3, p2);
     i= pc.end();
     QVERIFY(i-1==i3);
     i2= pc2.end();
     QVERIFY(i2-1!=i3);
     QCOMPARE(*(i2-1), *i3);
     foreach(QhullPoint p3, pc){ //Qt only
         QVERIFY(p3[0]>=0.0);
         QVERIFY(p3[0]<=5.0);
     }
     Coordinates::ConstIterator i4= pc.beginCoordinates();
     QCOMPARE(*i4, 0.0);
     Coordinates::Iterator i5= pc.beginCoordinates();
     QCOMPARE(*i5, 0.0);
     i4= pc.beginCoordinates(1);
     QCOMPARE(*i4, 2.0);
     i5= pc.beginCoordinates(1);
     QCOMPARE(*i5, 2.0);
     i4= pc.endCoordinates();
     QCOMPARE(*--i4, 5.0);
     i5= pc.endCoordinates();
     QCOMPARE(*--i5, 5.0);
 }//t_foreach
 
 void PointCoordinates_test::
 t_search()
 {
+    Qhull q;
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
-    PointCoordinates pc(2, "2-d points", 6, c);
+    PointCoordinates pc(q, 2, "2-d points", 6, c);
     QhullPoint p0= pc[0];
     QhullPoint p2= pc[2];
     QVERIFY(pc.contains(p0));
     QVERIFY(pc.contains(p2));
     QCOMPARE(pc.count(p0), 1);
     QCOMPARE(pc.indexOf(p2), 2);
     QCOMPARE(pc.lastIndexOf(p0), 0);
 }//t_search
 
 void PointCoordinates_test::
 t_modify()
 {
+    Qhull q;
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
-    PointCoordinates pc(2, "2-d points", 6, c);
+    PointCoordinates pc(q, 2, "2-d points", 6, c);
     coordT c3[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
-    PointCoordinates pc5(2);
+    PointCoordinates pc5(q, 2);
     pc5.append(6, c3); // 0-5
     QVERIFY(pc5==pc);
-    PointCoordinates pc2(2, "2-d");
+    PointCoordinates pc2(q, 2, "2-d");
     coordT c2[]= {6.0, 7.0, 8.0, 9.0, 10.0, 11.0};
     pc2.append(6, c2);
     QCOMPARE(pc2.count(), 3);
     pc2.append(14.0);
     QCOMPARE(pc2.count(), 3);
     QCOMPARE(pc2.extraCoordinatesCount(), 1);
     pc2.append(15.0); // 6-11, 14,15
     QCOMPARE(pc2.count(), 4);
     QCOMPARE(pc2.extraCoordinatesCount(), 0);
     QhullPoint p(pc[0]);
     pc2.append(p); // 6-11, 14,15, 0,1
     QCOMPARE(pc2.count(), 5);
     QCOMPARE(pc2.extraCoordinatesCount(), 0);
     QCOMPARE(pc2.lastIndexOf(p), 4);
     pc.append(pc2); // Invalidates p
     QCOMPARE(pc.count(), 8); // 0-11, 14,15, 0,1
     QCOMPARE(pc.extraCoordinatesCount(), 0);
     QCOMPARE(pc.lastIndexOf(pc[0]), 7);
     pc.appendComment(" operators");
     QCOMPARE(pc.comment(), std::string("2-d points operators"));
     pc.checkValid();
     // see t_append_points for appendPoints
     PointCoordinates pc3= pc+pc2;
     pc3.checkValid();
     QCOMPARE(pc3.count(), 13);
     QCOMPARE(pc3[6][0], 14.0);
     QCOMPARE(pc3[8][0], 6.0);
     pc3 += pc;
     QCOMPARE(pc3.count(), 21);
     QCOMPARE(pc3[14][0], 2.0);
     pc3 += 12.0;
     pc3 += 14.0;
     QCOMPARE(pc3.count(), 22);
     QCOMPARE(pc3.last()[0], 12.0);
     // QhullPoint p3= pc3.first(); // += throws error because append may move the data
     QhullPoint p3= pc2.first();
     pc3 += p3;
     QCOMPARE(pc3.count(), 23);
     QCOMPARE(pc3.last()[0], 6.0);
     pc3 << pc;
     QCOMPARE(pc3.count(), 31);
     QCOMPARE(pc3.last()[0], 0.0);
     pc3 << 12.0 << 14.0;
     QCOMPARE(pc3.count(), 32);
     QCOMPARE(pc3.last()[0], 12.0);
     PointCoordinates pc4(pc3);
     pc4.reserveCoordinates(100);
     QVERIFY(pc3==pc4);
 }//t_modify
 
 void PointCoordinates_test::
 t_append_points()
 {
-    PointCoordinates pc(2, "stringstream");
+    Qhull q;
+    PointCoordinates pc(q, 2, "stringstream");
     stringstream s("2 3 1 2 3 4 5 6");
     pc.appendPoints(s);
     QCOMPARE(pc.count(), 3);
 }//t_append_points
 
 void PointCoordinates_test::
 t_coord_iterator()
 {
-    PointCoordinates c(2);
+    Qhull q;
+    PointCoordinates c(q, 2);
     c << 0.0 << 1.0 << 2.0 << 3.0 << 4.0 << 5.0;
     PointCoordinatesIterator i(c);
     QhullPoint p0(c[0]);
     QhullPoint p1(c[1]);
     QhullPoint p2(c[2]);
     coordT c2[] = {-1.0, -2.0};
     QhullPoint p3(2, c2);
     PointCoordinatesIterator i2= c;
     QVERIFY(i.findNext(p1));
     QVERIFY(!i.findNext(p1));
     QVERIFY(!i.findNext(p2));
     QVERIFY(!i.findNext(p3));
     QVERIFY(i.findPrevious(p2));
     QVERIFY(!i.findPrevious(p2));
     QVERIFY(!i.findPrevious(p0));
     QVERIFY(!i.findPrevious(p3));
     QVERIFY(i2.findNext(p2));
     QVERIFY(i2.findPrevious(p0));
     QVERIFY(i2.findNext(p1));
     QVERIFY(i2.findPrevious(p0));
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
-    PointCoordinates c3;
+    PointCoordinates c3(q);
     PointCoordinatesIterator i3= c3;
     QVERIFY(!i3.hasNext());
     QVERIFY(!i3.hasPrevious());
     i3.toBack();
     QVERIFY(!i3.hasNext());
     QVERIFY(!i3.hasPrevious());
     QCOMPARE(i.peekPrevious(), p2);
     QCOMPARE(i.previous(), p2);
     QCOMPARE(i.previous(), p1);
     QCOMPARE(i.previous(), p0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), p0);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), p0);
     QCOMPARE(i.peekNext(), p1);
     QCOMPARE(i.next(), p1);
     QCOMPARE(i.next(), p2);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p0);
 }//t_coord_iterator
 
 void PointCoordinates_test::
 t_io()
 {
-    PointCoordinates c;
+    Qhull q;
+    PointCoordinates c(q);
     c << 1.0 << 2.0 << 3.0 << 1.0 << 2.0 << 3.0;
     ostringstream os;
     os << "PointCoordinates 0-d\n" << c;
     c.setDimension(2);
     os << "PointCoordinates 1-3-2\n" << c;
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("0"), 3);
     QCOMPARE(s.count("2"), 4);
 }//t_io
 
 }//orgQhull
 
 #include "moc/PointCoordinates_test.moc"
diff --git a/src/qhulltest/Point_test.cpp b/src/qhulltest/Point_test.cpp
index 2c533b3..bd181e1 100644
--- a/src/qhulltest/Point_test.cpp
+++ b/src/qhulltest/Point_test.cpp
@@ -1,238 +1,238 @@
 /****************************************************************************
 **
-** Copyright (C) 2009-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/Point_test.cpp#4 $$Change: 1490 $
-** $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $
+** Copyright (C) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/Point_test.cpp#5 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include 
 using std::cout;
 using std::endl;
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullPoint.h"
 
 #include "Qhull.h"
 
 namespace orgQhull {
 
 class Point_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void initTestCase();
     void t_construct();
     void t_getset();
     void t_operator();
     void t_const_iterator();
     void t_iterator();
     void t_point_iterator();
     // void t_mutable_point_iterator();
     // void t_io();
 };//Point_test
 
 void
 add_Point_test()
 {
     new Point_test();
 }
 
 void Point_test::
 initTestCase(){
     RboxPoints rcube("c");
     Qhull q(rcube, "");
     UsingQhullLib::setGlobals();
 }//initTestCase
 
 void Point_test::
 t_construct()
 {
     QhullPoint p;
     QCOMPARE(p.dimension(), 0);
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoint p2;
     p2.defineAs(3, c);
     QCOMPARE(p2.dimension(), 3);
     QCOMPARE(p2.coordinates(), c);
     coordT c2[]= {0.0, 1.0, 2.0};
     QhullPoint p3(3, c2);
     QVERIFY(p3==p2);
     QhullPoint p5(p3);
     QVERIFY(p5==p3);
 }//t_construct
 
 void Point_test::
 t_getset()
 {
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoint p(3, c);
     QCOMPARE(p.coordinates(), c);
     QCOMPARE(p.dimension(), 3);
     QCOMPARE(p[2], 2.0);
     QhullPoint p2(p);
     p2.defineAs(p);
     QVERIFY(p2==p);
     QVERIFY(p2.coordinates()==p.coordinates());
     QVERIFY(p2.dimension()==p.dimension());
     p2.setDimension(2);
     QCOMPARE(p2.dimension(), 2);
     QVERIFY(p2!=p);
     coordT c2[]= {0.0, 1.0};
     p2.setCoordinates(c2);
     QCOMPARE(p2.coordinates(), c2);
     p.defineAs(2, c);
     QVERIFY(p2==p);
     QCOMPARE(p[1], 1.0);
 }//t_getset
 
 void Point_test::
 t_operator()
 {
     QhullPoint p;
     QhullPoint p2(p);
     QVERIFY(p==p2);
     QVERIFY(!(p!=p2));
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoint p3(3, c);
     QVERIFY(p3!=p2);
     QhullPoint p4(p3);
     QVERIFY(p4==p3);
     coordT c5[]= {5.0, 6.0, 7.0};
     QhullPoint p5(3, c5);
     QVERIFY(p5!=p3);
     QCOMPARE(p5[1], 6.0);
     QCOMPARE(p5[0], 5.0);
     const coordT *c0= &p5[0];
     QCOMPARE(*c0, 5.0);
 }//t_operator
 
 void Point_test::
 t_const_iterator()
 {
     coordT c[]= {1.0, 2.0, 3.0};
     QhullPoint p(3, c);
     QhullPoint::const_iterator i(p.coordinates());
     QhullPoint::const_iterator i2= p.coordinates();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 2.0);
     QCOMPARE(*(i+1), i[1]);
     i= p.end();
     QVERIFY(i!=i2);
     i= i2;
     QVERIFY(i==i2);
     i= p.end();
     i= p.begin();
     QCOMPARE(*i, 1.0);
     QhullPoint::ConstIterator i3= p.end();
     QCOMPARE(*(i3-1), 3.0);
     QCOMPARE(*(i3-1), i3[-1]);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
 }//t_const_iterator
 
 
 void Point_test::
 t_iterator()
 {
     coordT c[]= {1.0, 2.0, 3.0};
     QhullPoint p(3, c);
     QhullPoint::Iterator i(p.coordinates());
     QhullPoint::iterator i2= p.coordinates();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     QCOMPARE(*i, 1.0);
     QCOMPARE(*(i+1), 2.0);
     QCOMPARE(*(i+1), i[1]);
     i= p.end();
     QVERIFY(i!=i2);
     i= i2;
     QVERIFY(i==i2);
     i= p.end();
     i= p.begin();
     QCOMPARE(*i, 1.0);
     QhullPoint::Iterator i3= p.end();
     QCOMPARE(*(i3-1), 3.0);
     QCOMPARE(*(i3-1), i3[-1]);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
     // compiler errors -- QhullPoint is const-only
     // QCOMPARE((i[0]= -10.0), -10.0);
     // coordT *c3= &i3[1];
 }//t_iterator
 
 void Point_test::
 t_point_iterator()
 {
     coordT c[]= {1.0, 3.0, 4.0};
     QhullPoint p(3, c);
     QhullPointIterator i(p);
     QhullPointIterator i2= p;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     i2.toFront();
     QVERIFY(!i.hasNext());
     QVERIFY(i.hasPrevious());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
 
     coordT c2[]= {1.0, 3.0, 4.0};
     QhullPoint p2(0, c2); // 0-dimensional
     i2= p2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekPrevious(), 4.0);
     QCOMPARE(i.previous(), 4.0);
     QCOMPARE(i.previous(), 3.0);
     QCOMPARE(i.previous(), 1.0);
     QVERIFY(!i.hasPrevious());
     QCOMPARE(i.peekNext(), 1.0);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), 1.0);
     QCOMPARE(i.peekNext(), 3.0);
     QCOMPARE(i.next(), 3.0);
     QCOMPARE(i.next(), 4.0);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), 1.0);
 }//t_point_iterator
 
 // No MutableQhullPointIterator since QhullPoint is const-only
 
 #if 0
 
 void Point_test::
 t_io()
 {
     QhullPoint p;
     cout<< "INFO:     empty point" << p << endl;
     const coordT c[]= {1.0, 3.0, 4.0};
     QhullPoint p2(2, c); // 2-dimensional
     cout<< "INFO:   " << p2 << endl;
 }//t_io
 
 error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class orgQhull::QhullPoint &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAVPoint@orgQhull@@@Z) referenced in function "private: void __thiscall orgQhull::Point_test::t_io(void)" (?t_io@Point_test@orgQhull@@AAEXXZ)
 
 #endif
 
 }//orgQhull
 
 #include "moc/Point_test.moc"
diff --git a/src/qhulltest/QhullFacetList_test.cpp b/src/qhulltest/QhullFacetList_test.cpp
index 3070647..2c0b5da 100644
--- a/src/qhulltest/QhullFacetList_test.cpp
+++ b/src/qhulltest/QhullFacetList_test.cpp
@@ -1,173 +1,200 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullFacetList_test.cpp#6 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullFacetList_test.cpp#7 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullFacetList.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "QhullVertexSet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacetList_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
-    void t_construct();
+    void t_construct_qh();
+    void t_construct_q();
     void t_convert();
     void t_readonly();
     void t_foreach();
     void t_io();
 };//QhullFacetList_test
 
 void
 add_QhullFacetList_test()
 {
     new QhullFacetList_test();
 }
 
 //Executed after each testcase
 void QhullFacetList_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullFacetList_test::
-t_construct()
+t_construct_qh()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacetList fs2= q.facetList();
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),6);
     QhullFacetList fs3(q.endFacet(), q.endFacet());
     QVERIFY(fs3.isEmpty());
     QhullFacetList fs4(q.endFacet().previous(), q.endFacet());
     QCOMPARE(fs4.count(), 1);
     QhullFacetList fs5(q.beginFacet(), q.endFacet());
     QCOMPARE(fs2.count(), fs5.count());
     QVERIFY(fs2==fs5);
     QhullFacetList fs6= fs2; // copy constructor
     QVERIFY(fs6==fs2);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 6u);
-}//t_construct
+    q.checkAndFreeQhullMemory();
+}//t_construct_qh
+
+void QhullFacetList_test::
+t_construct_q()
+{
+    RboxPoints rcube("c");
+    Qhull q(rcube,"QR0");  // rotated unit cube
+    QhullFacetList fs2= q.facetList();
+    QVERIFY(!fs2.isEmpty());
+    QCOMPARE(fs2.count(),6);
+    QhullFacetList fs3(q.endFacet(), q.endFacet());
+    QVERIFY(fs3.isEmpty());
+    QhullFacetList fs4(q.endFacet().previous(), q.endFacet());
+    QCOMPARE(fs4.count(), 1);
+    QhullFacetList fs5(q.beginFacet(), q.endFacet());
+    QCOMPARE(fs2.count(), fs5.count());
+    QVERIFY(fs2==fs5);
+    QhullFacetList fs6= fs2; // copy constructor
+    QVERIFY(fs6==fs2);
+    std::vector fv= fs2.toStdVector();
+    QCOMPARE(fv.size(), 6u);
+    q.checkAndFreeQhullMemory();
+}//t_construct_q
 
 void QhullFacetList_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0 QV2");  // rotated unit cube
     QhullFacetList fs2= q.facetList();
     QVERIFY(!fs2.isSelectAll());
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),3);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 3u);
     QList fv2= fs2.toQList();
     QCOMPARE(fv2.size(), 3);
     std::vector fv5= fs2.vertices_toStdVector();
     QCOMPARE(fv5.size(), 7u);
     QList fv6= fs2.vertices_toQList();
     QCOMPARE(fv6.size(), 7);
     fs2.selectAll();
     QVERIFY(fs2.isSelectAll());
     std::vector fv3= fs2.toStdVector();
     QCOMPARE(fv3.size(), 6u);
     QList fv4= fs2.toQList();
     QCOMPARE(fv4.size(), 6);
     std::vector fv7= fs2.vertices_toStdVector();
     QCOMPARE(fv7.size(), 8u);
     QList fv8= fs2.vertices_toQList();
     QCOMPARE(fv8.size(), 8);
+    q.checkAndFreeQhullMemory();
 }//t_convert
 
 //! Spot check properties and read-only.  See QhullLinkedList_test
 void QhullFacetList_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
     QhullFacetList fs= q.facetList();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 3);
     QCOMPARE(fs.first(), q.firstFacet());
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 6);
     fs.selectGood();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 3);
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 6);
     QhullFacet f= fs.first();
     QhullFacet f2= fs.last();
     fs.selectAll();
     QVERIFY(fs.contains(f));
     QVERIFY(fs.contains(f2));
     QVERIFY(f.isGood());
     QVERIFY(!f2.isGood());
     fs.selectGood();
     QVERIFY(fs.contains(f));
     QVERIFY(!fs.contains(f2));
+    q.checkAndFreeQhullMemory();
 }//t_readonly
 
 void QhullFacetList_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     // Spot check predicates and accessors.  See QhullLinkedList_test
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullFacetList fs= q.facetList();
     QVERIFY(fs.contains(q.firstFacet()));
     QhullFacet f= q.firstFacet().next();
     QVERIFY(fs.contains(f));
     QCOMPARE(fs.first(), *fs.begin());
     QCOMPARE(*(fs.end()-1), fs.last());
     QCOMPARE(fs.first(), q.firstFacet());
     QCOMPARE(*fs.begin(), q.beginFacet());
     QCOMPARE(*fs.end(), q.endFacet());
+    q.checkAndFreeQhullMemory();
 }//t_foreach
 
 void QhullFacetList_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
         QhullFacetList fs= q.facetList();
         ostringstream os;
         os << fs.print(); // Runs all print options
         os << "\nFacets only\n" << fs; 
         os << "\nVertices\n" << fs.printVertices()
         cout << os.str();
         QString facets= QString::fromStdString(os.str());
         QCOMPARE(facets.count("(v"), 7+12*3*2);
         QCOMPARE(facets.count(QRegExp("f\\d")), 3*7 + 13*3*2);
+        q.checkAndFreeQhullMemory();
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullFacetList_test.moc"
diff --git a/src/qhulltest/QhullFacetSet_test.cpp b/src/qhulltest/QhullFacetSet_test.cpp
index 7b9ae8f..f1de14b 100644
--- a/src/qhulltest/QhullFacetSet_test.cpp
+++ b/src/qhulltest/QhullFacetSet_test.cpp
@@ -1,153 +1,157 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullFacetSet_test.cpp#6 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullFacetSet_test.cpp#7 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullFacetSet.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacetSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_foreach();
     void t_io();
 };//QhullFacetSet_test
 
 void
 add_QhullFacetSet_test()
 {
     new QhullFacetSet_test();
 }
 
 //Executed after each testcase
 void QhullFacetSet_test::
 cleanup()
 {
     RoadTest::cleanup();
-    UsingLibQhull::checkQhullMemoryEmpty();
 }
 
 void QhullFacetSet_test::
 t_construct()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullFacetSet fs2= f.neighborFacets();
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),4);
     QhullFacetSet fs4= fs2; // copy constructor
     QVERIFY(fs4==fs2);
     QhullFacetSet fs3(q.qhullQh()->facet_mergeset);
     QVERIFY(fs3.isEmpty());
+    q.checkAndFreeQhullMemory();
 }//t_construct
 
 void QhullFacetSet_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q2(rcube,"QR0 QV2");  // rotated unit cube
     QhullFacet f2= q2.firstFacet();
     QhullFacetSet fs2= f2.neighborFacets();
     QVERIFY(!fs2.isSelectAll());
     QCOMPARE(fs2.count(),2);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 2u);
     QList fv2= fs2.toQList();
     QCOMPARE(fv2.size(), 2);
     fs2.selectAll();
     QVERIFY(fs2.isSelectAll());
     std::vector fv3= fs2.toStdVector();
     QCOMPARE(fv3.size(), 4u);
     QList fv4= fs2.toQList();
     QCOMPARE(fv4.size(), 4);
+    q2.checkAndFreeQhullMemory();
 }//t_convert
 
 //! Spot check properties and read-only.  See QhullSet_test
 void QhullFacetSet_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 4);
     fs.selectGood();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     QhullFacet f= fs.first();
     QhullFacet f2= fs.last();
     fs.selectAll();
     QVERIFY(fs.contains(f));
     QVERIFY(fs.contains(f2));
     QVERIFY(f.isGood());
     QVERIFY(!f2.isGood());
     fs.selectGood();
     QVERIFY(fs.contains(f));
     QVERIFY(!fs.contains(f2));
+    q.checkAndFreeQhullMemory();
 }//t_readonly
 
 void QhullFacetSet_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     // Spot check predicates and accessors.  See QhullLinkedList_test
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.contains(q.firstFacet()));
     QVERIFY(fs.contains(fs.first()));
     QhullFacet f= q.firstFacet().next();
     if(!fs.contains(f)){
         f= f.next();
     }
     QVERIFY(fs.contains(f));
     QCOMPARE(fs.first(), *fs.begin());
     QCOMPARE(*(fs.end()-1), fs.last());
+    q.checkAndFreeQhullMemory();
 }//t_foreach
 
 void QhullFacetSet_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
         QhullFacetSet fs= q.firstFacet().neighborFacets();
         ostringstream os;
         os << fs.print("Neighbors of first facet with point 0");
         os << fs.printIdentifiers("\nFacet identifiers: ");
         cout << os.str();
         QString facets= QString::fromStdString(os.str());
         QCOMPARE(facets.count(QRegExp(" f[0-9]")), 2+13*2);
+        q.checkAndFreeQhullMemory();
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullFacetSet_test.moc"
diff --git a/src/qhulltest/QhullFacet_test.cpp b/src/qhulltest/QhullFacet_test.cpp
index 1ea4795..11cb7f4 100644
--- a/src/qhulltest/QhullFacet_test.cpp
+++ b/src/qhulltest/QhullFacet_test.cpp
@@ -1,264 +1,283 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullFacet_test.cpp#9 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullFacet_test.cpp#10 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullFacet.h"
 #include "QhullError.h"
 #include "Coordinates.h"
 #include "RboxPoints.h"
 #include "QhullFacetList.h"
 #include "QhullFacetSet.h"
 #include "QhullPointSet.h"
 #include "QhullRidge.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
+    void t_construct_qh();
     void t_constructConvert();
     void t_getSet();
     void t_value();
     void t_foreach();
     void t_io();
 };//QhullFacet_test
 
 void
 add_QhullFacet_test()
 {
     new QhullFacet_test();
 }
 
 //Executed after each testcase
 void QhullFacet_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
+void QhullFacet_test::
+t_construct_qh()
+{
+    // Qhull.runQhull() constructs QhullFacets as facetT
+    QhullQh qh;  
+    QhullFacet f(qh);
+    QVERIFY(!f.isDefined());
+    QCOMPARE(f.dimension(),0);
+}//t_construct_qh
+
 void QhullFacet_test::
 t_constructConvert()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
-    QhullFacet f;
+    Qhull q2;  
+    QhullFacet f(q2);
     QVERIFY(!f.isDefined());
     QCOMPARE(f.dimension(),0);
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullFacet f2(q.beginFacet());
     QCOMPARE(f2.dimension(),3);
     f= f2; // copy assignment
     QVERIFY(f.isDefined());
     QCOMPARE(f.dimension(),3);
     QhullFacet f5= f2;
     QVERIFY(f5==f2);
     QVERIFY(f5==f);
     QhullFacet f3= f2.getFacetT();
     QCOMPARE(f,f3);
     QhullFacet f4= f2.getBaseT();
     QCOMPARE(f,f4);
+    q.checkAndFreeQhullMemory();
+    q2.checkAndFreeQhullMemory();
 }//t_constructConvert
 
 void QhullFacet_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QCOMPARE(q.vertexCount(), 8);
         QhullFacetListIterator i(q.facetList());
         while(i.hasNext()){
             const QhullFacet f= i.next();
             cout << f.id() << endl;
             QCOMPARE(f.dimension(),3);
             QVERIFY(f.id()>0 && f.id()<=39);
             QVERIFY(f.isDefined());
             if(i.hasNext()){
                 QCOMPARE(f.next(), i.peekNext());
                 QVERIFY(f.next()!=f);
             }
             QVERIFY(i.hasPrevious());
             QCOMPARE(f, i.peekPrevious());
         }
         QhullFacetListIterator i2(i);
         QEXPECT_FAIL("", "ListIterator copy constructor not reset to BOT", Continue);
         QVERIFY(!i2.hasPrevious());
 
         // test tricoplanarOwner
         QhullFacet facet = q.beginFacet();
         QhullFacet tricoplanarOwner = facet.tricoplanarOwner();
         int tricoplanarCount= 0;
         i.toFront();
         while(i.hasNext()){
             const QhullFacet f= i.next();
             if(f.tricoplanarOwner()==tricoplanarOwner){
                 tricoplanarCount++;
             }
         }
         QCOMPARE(tricoplanarCount, 2);
         int tricoplanarCount2= 0;
         foreach (QhullFacet f, q.facetList()){  // Qt only
             QhullHyperplane h= f.hyperplane();
             cout << "Hyperplane: " << h << endl;
             QCOMPARE(h.count(), 3);
             QCOMPARE(h.offset(), -0.5);
             double n= h.norm();
             QCOMPARE(n, 1.0);
             QhullHyperplane hi= f.innerplane();
             QCOMPARE(hi.count(), 3);
             double innerOffset= hi.offset()+0.5;
             cout << "InnerPlane: " << hi << "innerOffset+0.5 " << innerOffset << endl;
             QVERIFY(innerOffset >= 0.0);
             QhullHyperplane ho= f.outerplane();
             QCOMPARE(ho.count(), 3);
             double outerOffset= ho.offset()+0.5;
             cout << "OuterPlane: " << ho << "outerOffset+0.5 " << outerOffset << endl;
             QVERIFY(outerOffset <= 0.0);
             QVERIFY(outerOffset-innerOffset < 1e-7);
             for(int k= 0; k<3; k++){
                 QVERIFY(ho[k]==hi[k]);
                 QVERIFY(ho[k]==h[k]);
             }
             QhullPoint center= f.getCenter();
             cout << "Center: " << center << endl;
             double d= f.distance(center);
             QVERIFY(d < innerOffset-outerOffset);
             QhullPoint center2= f.getCenter(qh_PRINTcentrums);
             QCOMPARE(center, center2);
             if(f.tricoplanarOwner()==tricoplanarOwner){
                 tricoplanarCount2++;
             }
         }
         QCOMPARE(tricoplanarCount2, 2);
         Qhull q2(rcube,"d Qz Qt QR0");  // 3-d triangulation of Delaunay triangulation (the cube)
         QhullFacet f2= q2.firstFacet();
         QhullPoint center3= f2.getCenter(qh_PRINTtriangles);
         QCOMPARE(center3.dimension(), 3);
         QhullPoint center4= f2.getCenter();
         QCOMPARE(center4.dimension(), 3);
         for(int k= 0; k<3; k++){
             QVERIFY(center4[k]==center3[k]);
         }
         Qhull q3(rcube,"v Qz QR0");  // Voronoi diagram of a cube (one vertex)
 
-        UsingLibQhull::setGlobalDistanceEpsilon(1e-12); // Voronoi vertices are not necessarily within distance episilon
+        q->setFactorEpsilon(100); // Voronoi vertices are not necessarily within distance episilon
         foreach(QhullFacet f, q3.facetList()){ //Qt only
             if(f.isGood()){
                 QhullPoint p= f.voronoiVertex(q3.runId());
                 cout << p.print(q3.runId(), "Voronoi vertex: ")
-                    << " DistanceEpsilon " << UsingLibQhull::globalDistanceEpsilon() << endl;
+                    << " DistanceEpsilon " << q->distanceEpsilon() << endl;
                 QCOMPARE(p, q3.origin());
             }
         }
+        q.checkAndFreeQhullMemory();
+        q2.checkAndFreeQhullMemory();
+        q3.checkAndFreeQhullMemory();
     }
 }//t_getSet
 
 void QhullFacet_test::
 t_value()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         coordT c[]= {0.0, 0.0, 0.0};
         foreach (QhullFacet f, q.facetList()){  // Qt only
             double d= f.distance(q.origin());
             QCOMPARE(d, -0.5);
             double d0= f.distance(c);
             QCOMPARE(d0, -0.5);
             double facetArea= f.facetArea();
             QCOMPARE(facetArea, 1.0);
             #if qh_MAXoutside
                 double maxoutside= f.getFacetT()->maxoutside;
                 QVERIFY(maxoutside<1e-7);
             #endif
         }
     }
+    q.checkAndFreeQhullMemory();
 }//t_value
 
 void QhullFacet_test::
 t_foreach()
 {
     RboxPoints rcube("c W0 300");  // cube plus 300 points on its surface
     {
         Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube
         int coplanarCount= 0;
         foreach(const QhullFacet f, q.facetList()){
             QhullPointSet coplanars= f.coplanarPoints();
             coplanarCount += coplanars.count();
             QhullFacetSet neighbors= f.neighborFacets();
             QCOMPARE(neighbors.count(), 4);
             QhullPointSet outsides= f.outsidePoints();
             QCOMPARE(outsides.count(), 0);
             QhullRidgeSet ridges= f.ridges();
             QCOMPARE(ridges.count(), 4);
             QhullVertexSet vertices= f.vertices();
             QCOMPARE(vertices.count(), 4);
             int ridgeCount= 0;
             QhullRidge r= ridges.first();
             for(int r0= r.id(); ridgeCount==0 || r.id()!=r0; r= r.nextRidge3d(f)){
                 ++ridgeCount;
                 if(!r.hasNextRidge3d(f)){
                     QFAIL("Unexpected simplicial facet.  They only have ridges to non-simplicial neighbors.");
                 }
             }
             QCOMPARE(ridgeCount, 4);
         }
         QCOMPARE(coplanarCount, 300);
     }
+    q.checkAndFreeQhullMemory();
 }//t_foreach
 
 void QhullFacet_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullFacet f= q.beginFacet();
         cout << f;
         ostringstream os;
         os << f.printHeader();
         os << f.printFlags("    - flags:");
         os << f.printCenter(qh_PRINTfacets, "    - center:");
         os << f.printRidges();
         cout << os.str();
         ostringstream os2;
         os2 << f.print();  // invokes print*()
         QString facetString2= QString::fromStdString(os2.str());
         facetString2.replace(QRegExp("\\s\\s+"), " ");
         ostringstream os3;
         q.setOutputStream(&os3);
         q.outputQhull("f");
         QString facetsString= QString::fromStdString(os3.str());
         QString facetString3= facetsString.mid(facetsString.indexOf("- f1\n"));
         facetString3= facetString3.left(facetString3.indexOf("\n- f")+1);
         facetString3.replace(QRegExp("\\s\\s+"), " ");
         QCOMPARE(facetString2, facetString3);
     }
+    q.checkAndFreeQhullMemory();
 }//t_io
 
 // toQhullFacet is static_cast only
 
 }//orgQhull
 
 #include "moc/QhullFacet_test.moc"
diff --git a/src/qhulltest/QhullHyperplane_test.cpp b/src/qhulltest/QhullHyperplane_test.cpp
index 0df84fd..483f673 100644
--- a/src/qhulltest/QhullHyperplane_test.cpp
+++ b/src/qhulltest/QhullHyperplane_test.cpp
@@ -1,412 +1,421 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullHyperplane_test.cpp#8 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullHyperplane_test.cpp#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include 
 #include "RoadTest.h"
 
 #include "QhullHyperplane.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "Qhull.h"
 #include 
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullHyperplane_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_define();
     void t_value();
     void t_operator();
     void t_iterator();
     void t_const_iterator();
     void t_qhullHyperplane_iterator();
     void t_io();
 };//QhullHyperplane_test
 
 void
 add_QhullHyperplane_test()
 {
     new QhullHyperplane_test();
 }
 
 //Executed after each testcase
 void QhullHyperplane_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullHyperplane_test::
 t_construct()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullHyperplane h;
     QVERIFY(!h.isDefined());
     QCOMPARE(h.dimension(),0);
     QCOMPARE(h.coordinates(),static_cast(0));
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullHyperplane h2(f.hyperplane());
     QVERIFY(h2.isDefined());
     QCOMPARE(h2.dimension(),3);
     // h= h2;  // copy assignment disabled, ambiguous
     QhullHyperplane h3(h2.dimension(), h2.coordinates(), h2.offset());
     QCOMPARE(h2, h3);
     QhullHyperplane h5= h2; // copy constructor
     QVERIFY(h5==h2);
+    q.checkAndFreeQhullMemory();
 }//t_construct
 
 void QhullHyperplane_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullHyperplane h= q.firstFacet().hyperplane();
     std::vector fs= h.toStdVector();
     QCOMPARE(fs.size(), 4u);
     double offset= fs.back();
     fs.pop_back();
     QCOMPARE(offset, -0.5);
 
     double squareNorm= inner_product(fs.begin(), fs.end(), fs.begin(), 0.0);
     QCOMPARE(squareNorm, 1.0);
     QList qs= h.toQList();
     QCOMPARE(qs.size(), 4);
     double offset2= qs.takeLast();
     QCOMPARE(offset2, -0.5);
     double squareNorm2= std::inner_product(qs.begin(), qs.end(), qs.begin(), 0.0);
     QCOMPARE(squareNorm2, 1.0);
+    q.checkAndFreeQhullMemory();
 }//t_convert
 
 void QhullHyperplane_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullFacetList fs= q.facetList();
         QhullFacetListIterator i(fs);
         while(i.hasNext()){
             QhullFacet f= i.next();
             QhullHyperplane h= f.hyperplane();
             int id= f.id();
             cout << "h" << id << endl;
             QVERIFY(h.isDefined());
             QCOMPARE(h.dimension(),3);
             const coordT *c= h.coordinates();
             coordT *c2= h.coordinates();
             QCOMPARE(c, c2);
             const coordT *c3= h.begin();
             QCOMPARE(c, c3);
             QCOMPARE(h.offset(), -0.5);
             int j= h.end()-h.begin();
             QCOMPARE(j, 3);
             double squareNorm= std::inner_product(h.begin(), h.end(), h.begin(), 0.0);
             QCOMPARE(squareNorm, 1.0);
         }
         QhullHyperplane h2= fs.first().hyperplane();
         QhullHyperplane h3= fs.last().hyperplane();
         QVERIFY(h2!=h3);
         QVERIFY(h3.coordinates()!=h2.coordinates());
+        q.checkAndFreeQhullMemory();
     }
 }//t_readonly
 
 void QhullHyperplane_test::
 t_define()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullFacetList fs= q.facetList();
         QhullHyperplane h= fs.first().hyperplane();
         QhullHyperplane h2= h;
         QVERIFY(h==h2);
         QhullHyperplane h3= fs.last().hyperplane();
         QVERIFY(h2!=h3);
 
         QhullHyperplane h4= h3;
         h4.defineAs(h2);
         QVERIFY(h2==h4);
         QhullHyperplane p5= h3;
         p5.defineAs(h2.dimension(), h2.coordinates(), h2.offset());
         QVERIFY(h2==p5);
         QhullHyperplane h6= h3;
         h6.setCoordinates(h2.coordinates());
         QCOMPARE(h2.coordinates(), h6.coordinates());
         h6.setOffset(h2.offset());
         QCOMPARE(h2.offset(), h6.offset());
         QVERIFY(h2==h6);
         h6.setDimension(2);
         QCOMPARE(h6.dimension(), 2);
         QVERIFY(h2!=h6);
+        q.checkAndFreeQhullMemory();
     }
 }//t_define
 
 void QhullHyperplane_test::
 t_value()
 {
     RboxPoints rcube("c G1");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     const QhullHyperplane h= q.firstFacet().hyperplane();
     double dist= h.distance(q.origin());
     QCOMPARE(dist, -1.0);
     double norm= h.norm();
     QCOMPARE(norm, 1.0);
+    q.checkAndFreeQhullMemory();
 }//t_value
 
 void QhullHyperplane_test::
 t_operator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     const QhullHyperplane h= q.firstFacet().hyperplane();
     //operator== and operator!= tested elsewhere
     const coordT *c= h.coordinates();
     for(int k=h.dimension(); k--; ){
         QCOMPARE(c[k], h[k]);
     }
     //h[0]= 10.0; // compiler error, const
     QhullHyperplane h2= q.firstFacet().hyperplane();
     h2[0]= 10.0;  // Overwrites Hyperplane coordinate!
     QCOMPARE(h2[0], 10.0);
+    q.checkAndFreeQhullMemory();
 }//t_operator
 
 void QhullHyperplane_test::
 t_iterator()
 {
     RboxPoints rcube("c");
     {
         QhullHyperplane h2;
         QCOMPARE(h2.begin(), h2.end());
         QCOMPARE(h2.count(), 0);
         QCOMPARE(h2.size(), 0u);
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullHyperplane h= q.firstFacet().hyperplane();
         QCOMPARE(h.count(), 3);
         QCOMPARE(h.size(), 3u);
         QhullHyperplane::Iterator i= h.begin();
         QhullHyperplane::iterator i2= h.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= h.begin();
         QVERIFY(i==i2);
         i2= h.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, h[0]);
         QCOMPARE(d2, h[2]);
         QhullHyperplane::Iterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), h[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         QhullHyperplane::ConstIterator i4= h.begin();
         QVERIFY(i==i4); // iterator COMP const_iterator
         QVERIFY(i<=i4);
         QVERIFY(i>=i4);
         QVERIFY(i4==i); // const_iterator COMP iterator
         QVERIFY(i4<=i);
         QVERIFY(i4>=i);
         QVERIFY(i>=i4);
         QVERIFY(i4<=i);
         QVERIFY(i2!=i4);
         QVERIFY(i2>i4);
         QVERIFY(i2>=i4);
         QVERIFY(i4!=i2);
         QVERIFY(i4i);
         QVERIFY(i4>=i);
 
         i= h.begin();
         i2= h.begin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, h[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, h.begin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2 += 3, h.end());
         QCOMPARE(i2 -= 3, h.begin());
         QCOMPARE(i2+0, h.begin());
         QCOMPARE(i2+3, h.end());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, h.begin());
         QCOMPARE(i2-i, 3);
 
         //h.begin end tested above
 
         // QhullHyperplane is const-only
+        q.checkAndFreeQhullMemory();
     }
 }//t_iterator
 
 void QhullHyperplane_test::
 t_const_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullHyperplane h= q.firstFacet().hyperplane();
         QhullHyperplane::ConstIterator i= h.begin();
         QhullHyperplane::const_iterator i2= h.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= h.begin();
         QVERIFY(i==i2);
         i2= h.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, h[0]);
         QCOMPARE(d2, h[2]);
         QhullHyperplane::ConstIterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), h[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         // See t_iterator for const_iterator COMP iterator
 
         i= h.begin();
         i2= h.constBegin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, h[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, h.constBegin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2+=3, h.constEnd());
         QCOMPARE(i2-=3, h.constBegin());
         QCOMPARE(i2+0, h.constBegin());
         QCOMPARE(i2+3, h.constEnd());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, h.constBegin());
         QCOMPARE(i2-i, 3);
 
         // QhullHyperplane is const-only
+        q.checkAndFreeQhullMemory();
     }
 }//t_const_iterator
 
 void QhullHyperplane_test::
 t_qhullHyperplane_iterator()
 {
     QhullHyperplane h2;
     QhullHyperplaneIterator i= h2;
     QCOMPARE(h2.dimension(), 0);
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullHyperplane h = q.firstFacet().hyperplane();
     QhullHyperplaneIterator i2(h);
     QCOMPARE(h.dimension(), 3);
     i= h;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     // i at front, i2 at end/back, 3 coordinates
     QCOMPARE(i.peekNext(), h[0]);
     QCOMPARE(i2.peekPrevious(), h[2]);
     QCOMPARE(i2.previous(), h[2]);
     QCOMPARE(i2.previous(), h[1]);
     QCOMPARE(i2.previous(), h[0]);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), h[0]);
     // i.peekNext()= 1.0; // compiler error, i is const
     QCOMPARE(i.next(), h[0]);
     QCOMPARE(i.peekNext(), h[1]);
     QCOMPARE(i.next(), h[1]);
     QCOMPARE(i.next(), h[2]);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), h[0]);
+    q.checkAndFreeQhullMemory();
 }//t_qhullHyperplane_iterator
 
 void QhullHyperplane_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullHyperplane h= q.firstFacet().hyperplane();
         ostringstream os;
         os << "Hyperplane:\n";
         os << h;
         os << "Hyperplane as print(), FIXUP drop?\n";
         os << h.print();
         os << h.print(" and a message ", " offset ");
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("1"), 3);
         // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
+        q.checkAndFreeQhullMemory();
     }
 }//t_io
 
 
 }//orgQhull
 
 #include "moc/QhullHyperplane_test.moc"
diff --git a/src/qhulltest/QhullLinkedList_test.cpp b/src/qhulltest/QhullLinkedList_test.cpp
index 873fc59..2a60ff7 100644
--- a/src/qhulltest/QhullLinkedList_test.cpp
+++ b/src/qhulltest/QhullLinkedList_test.cpp
@@ -1,328 +1,335 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullLinkedList_test.cpp#6 $$Change: 1708 $
-** $DateTime: 2014/03/26 19:13:56 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullLinkedList_test.cpp#7 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullLinkedList.h"
 #include "Qhull.h"
 
 namespace orgQhull {
 
 class QhullLinkedList_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_element();
     void t_search();
     void t_iterator();
     void t_const_iterator();
     void t_QhullLinkedList_iterator();
     void t_io();
 };//QhullLinkedList_test
 
 void
 add_QhullLinkedList_test()
 {
     new QhullLinkedList_test();
 }
 
 //Executed after each testcase
 void QhullLinkedList_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullLinkedList_test::
 t_construct()
 {
     // QhullLinkedList vs; //private (compiler error).  No memory allocation
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QhullVertexList vs = QhullVertexList(q.beginVertex(), q.endVertex());
         QCOMPARE(vs.count(), 8);
         QCOMPARE(vs.size(), 8u);
         QVERIFY(!vs.isEmpty());
         QhullVertexList vs2 = q.vertexList();
         QCOMPARE(vs2.count(), 8);
         QCOMPARE(vs2.size(),8u);
         QVERIFY(!vs2.isEmpty());
         QVERIFY(vs==vs2);
         // vs= vs2; // disabled.  Would not copy the vertices
         QhullVertexList vs3= vs2; // copy constructor
         QVERIFY(vs3==vs2);
+        q.checkAndFreeQhullMemory();
     }
 }//t_construct
 
 void QhullLinkedList_test::
 t_convert()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QhullVertexList vs = q.vertexList();
         QCOMPARE(vs.size(), 8u);
         QVERIFY(!vs.isEmpty());
         std::vector vs2= vs.toStdVector();
         QCOMPARE(vs2.size(), vs.size());
         QhullVertexList::Iterator i= vs.begin();
         for(int k= 0; k<(int)vs2.size(); k++){
             QCOMPARE(vs2[k], *i++);
         }
         QList vs3= vs.toQList();
         QCOMPARE(vs3.count(), vs.count());
         i= vs.begin();
         for(int k= 0; k
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullPointSet.h"
 #include "RboxPoints.h"
 #include "QhullPoint.h"
 #include "QhullFacet.h"
 #include "QhullFacetList.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 
 namespace orgQhull {
 
 class QhullPointSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_element();
     void t_iterator();
     void t_const_iterator();
     void t_search();
     void t_pointset_iterator();
     void t_io();
 };//QhullPointSet_test
 
 void
 add_QhullPointSet_test()
 {
     new QhullPointSet_test();
 }
 
 //Executed after each testcase
 void QhullPointSet_test::
 cleanup()
 {
     RoadTest::cleanup();
 }
 
 void QhullPointSet_test::
 t_construct()
 {
     // Default constructor is disallowed (i.e., private)
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     int coplanarCount= 0;
     foreach(QhullFacet f, q.facetList()){
         QhullPointSet ps(q, f.getFacetT()->outsideset);
         QVERIFY(ps.isEmpty());
         QCOMPARE(ps.count(), 0);
         QCOMPARE(ps.size(), 0u);
         QhullPointSet ps2(q.qh(), f.getFacetT()->coplanarset);
         QVERIFY(!ps2.isEmpty());
         coplanarCount += ps2.count();
         QCOMPARE(ps2.count(), (int)ps2.size());
         QhullPointSet ps3(ps2);
         QVERIFY(!ps3.isEmpty());
         QCOMPARE(ps3.count(), ps2.count());
         QVERIFY(ps3==ps2);
         QVERIFY(ps3!=ps);
         QhullPointSet ps4= ps3;
         QVERIFY(ps4==ps2);
     }
     QCOMPARE(coplanarCount, 1000);
     q.checkAndFreeQhullMemory();
 }//t_construct
 
 void QhullPointSet_test::
 t_convert()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=1);   // Sometimes no coplanar points
     std::vector vs= ps.toStdVector();
     QCOMPARE(vs.size(), ps.size());
     QhullPoint p= ps[0];
     QhullPoint p2= vs[0];
     QCOMPARE(p, p2);
     QList qs= ps.toQList();
     QCOMPARE(qs.size(), static_cast(ps.size()));
     QhullPoint p3= qs[0];
     QCOMPARE(p3, p);
     q.checkAndFreeQhullMemory();
 }//t_convert
 
 // readonly tested in t_construct
 //   empty, isEmpty, ==, !=, size
 
 void QhullPointSet_test::
 t_element()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPoint p= ps[0];
     QCOMPARE(p, ps[0]);
     QhullPoint p2= ps[ps.count()-1];
     QCOMPARE(ps.at(1), ps[1]);
     QCOMPARE(ps.second(), ps[1]);
     QCOMPARE(ps.first(), p);
     QCOMPARE(ps.front(), ps.first());
     QCOMPARE(ps.last(), p2);
     QCOMPARE(ps.back(), ps.last());
     QhullPoint p8(q);
     QCOMPARE(ps.value(2), ps[2]);
     QCOMPARE(ps.value(-1), p8);
     QCOMPARE(ps.value(ps.count()), p8);
     QCOMPARE(ps.value(ps.count(), p), p);
     QVERIFY(ps.value(1, p)!=p);
     QhullPointSet ps8= f.coplanarPoints();
     QhullPointSet::Iterator i= ps8.begin();
     foreach(QhullPoint p9, ps){  // Qt only
         QCOMPARE(p9.dimension(), 3);
         QCOMPARE(p9, *i++);
     }
     q.checkAndFreeQhullMemory();
 }//t_element
 
 void QhullPointSet_test::
 t_iterator()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPointSet::Iterator i= ps.begin();
     QhullPointSet::iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p= *i;
     QCOMPARE(p.dimension(), q.dimension());
     QCOMPARE(p, ps[0]);
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p2.dimension(), q.dimension());
     QCOMPARE(p2, ps.last());
     QhullPointSet::Iterator i5(i2);
     QCOMPARE(*i2, *i5);
     QhullPointSet::Iterator i3= i+1;
     QVERIFY(i!=i3);
     QCOMPARE(i[1], *i3);
     (i3= i)++;
     QCOMPARE((*i3)[0], ps[1][0]);
     QCOMPARE((*i3).dimension(), 3);
 
     QVERIFY(i==i);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
 
     QhullPointSet::ConstIterator i4= ps.begin();
     QVERIFY(i==i4); // iterator COMP const_iterator
     QVERIFY(i<=i4);
     QVERIFY(i>=i4);
     QVERIFY(i4==i); // const_iterator COMP iterator
     QVERIFY(i4<=i);
     QVERIFY(i4>=i);
     QVERIFY(i>=i4);
     QVERIFY(i4<=i);
     QVERIFY(i2!=i4);
     QVERIFY(i2>i4);
     QVERIFY(i2>=i4);
     QVERIFY(i4!=i2);
     QVERIFY(i4i);
     QVERIFY(i4>=i);
     i4= ps.constBegin();
     QVERIFY(i==i4); // iterator COMP const_iterator
     QCOMPARE(i4+ps.count(), ps.constEnd());
 
     i= ps.begin();
     i2= ps.begin();
     QCOMPARE(i, i2++);
     QCOMPARE(*i2, ps[1]);
     QCOMPARE(++i, i2);
     QCOMPARE(i, i2--);
     QCOMPARE(i2, ps.begin());
     QCOMPARE(--i, i2);
     QCOMPARE(i2+=ps.count(), ps.end());
     QCOMPARE(i2-=ps.count(), ps.begin());
     QCOMPARE(i2+0, ps.begin());
     QCOMPARE(i2+ps.count(), ps.end());
     i2 += ps.count();
     i= i2-0;
     QCOMPARE(i, i2);
     i= i2-ps.count();
     QCOMPARE(i, ps.begin());
     QCOMPARE(i2-i, ps.count());
 
     //ps.begin end tested above
 
     // QhullPointSet is const-only
     q.checkAndFreeQhullMemory();
 }//t_iterator
 
 void QhullPointSet_test::
 t_const_iterator()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPointSet::ConstIterator i= ps.begin();
     QhullPointSet::const_iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
 
     // See t_iterator for const_iterator COMP iterator
 
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p= *i; // QhullPoint is the base class for QhullPointSet::iterator
     QCOMPARE(p.dimension(), q.dimension());
     QCOMPARE(p, ps[0]);
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p2.dimension(), q.dimension());
     QCOMPARE(p2, ps.last());
     QhullPointSet::ConstIterator i5(i2);
     QCOMPARE(*i2, *i5);
 
 
     QhullPointSet::ConstIterator i3= i+1;
     QVERIFY(i!=i3);
     QCOMPARE(i[1], *i3);
 
     QVERIFY(i==i);
     QVERIFY(i!=i3);
     QVERIFY(ii);
     QVERIFY(i3>=i);
 
     // QhullPointSet is const-only
     q.checkAndFreeQhullMemory();
 }//t_const_iterator
 
 
 void QhullPointSet_test::
 t_search()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPoint p= ps.first();
     QhullPoint p2= ps.last();
     QVERIFY(ps.contains(p));
     QVERIFY(ps.contains(p2));
     QVERIFY(p!=p2);
     QhullPoint p3= ps[2];
     QVERIFY(ps.contains(p3));
     QVERIFY(p!=p3);
     QCOMPARE(ps.indexOf(p), 0);
     QCOMPARE(ps.indexOf(p2), ps.count()-1);
     QCOMPARE(ps.indexOf(p3), 2);
     QhullPoint p4(q);
     QCOMPARE(ps.indexOf(p4), -1);
     QCOMPARE(ps.lastIndexOf(p), 0);
     QCOMPARE(ps.lastIndexOf(p2), ps.count()-1);
     QCOMPARE(ps.lastIndexOf(p3), 2);
     QCOMPARE(ps.lastIndexOf(p4), -1);
     q.checkAndFreeQhullMemory();
 }//t_search
 
 void QhullPointSet_test::
 t_pointset_iterator()
 {
     RboxPoints rcube("c W0 1000");
     Qhull q(rcube,"Qc");  // cube with 1000 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps2= f.outsidePoints();
     QVERIFY(ps2.count()==0); // No outside points after constructing the convex hull
     QhullPointSetIterator i2= ps2;
     QCOMPARE(i2.countRemaining(), 0);
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
 
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     QhullPointSetIterator i(ps);
     i2= ps;
     QCOMPARE(i2.countRemaining(), ps.count());
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     QCOMPARE(i2.countRemaining(), 0);
     i.toFront();
     QCOMPARE(i.countRemaining(), ps.count());
     QCOMPARE(i2.countRemaining(), 0);
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullPoint p= ps[0];
     QhullPoint p2(ps[0]);
     QCOMPARE(p, p2);
     QVERIFY(p==p2);
     QhullPoint p3(ps.last());
  // p2[0]= 0.0;
     QVERIFY(p==p2);
     QCOMPARE(i2.peekPrevious(), p3);
     QCOMPARE(i2.previous(), p3);
     QCOMPARE(i2.previous(), ps[ps.count()-2]);
     QVERIFY(i2.hasPrevious());
     QCOMPARE(i.peekNext(), p);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), p);
     QCOMPARE(i.countRemaining(), ps.count()-1);
     QhullPoint p4= i.peekNext();
     QVERIFY(p4!=p3);
     QCOMPARE(i.next(), p4);
     QVERIFY(i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p);
     q.checkAndFreeQhullMemory();
 }//t_pointset_iterator
 
 void QhullPointSet_test::
 t_io()
 {
     ostringstream os;
     RboxPoints rcube("c W0 120");
     Qhull q(rcube,"Qc");  // cube with 100 coplanar points
     QhullFacet f= q.firstFacet();
     QhullPointSet ps= f.coplanarPoints();
     QVERIFY(ps.count()>=3);  // Sometimes no coplanar points
     os << "QhullPointSet from coplanarPoints\n" << ps << endl;
     os << ps.print("\nWith message\n");
     os << ps.printIdentifiers("\nCoplanar points: ");
     os << "\nAs a point set:\n";
     os << ps;
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count(" 0.5\n"), 3*ps.count());
     QCOMPARE(s.count("p"), ps.count()+4);
     q.checkAndFreeQhullMemory();
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullPointSet_test.moc"
diff --git a/src/qhulltest/QhullPoint_test.cpp b/src/qhulltest/QhullPoint_test.cpp
index 58fbac5..a7d4eba 100644
--- a/src/qhulltest/QhullPoint_test.cpp
+++ b/src/qhulltest/QhullPoint_test.cpp
@@ -1,447 +1,447 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullPoint_test.cpp#10 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullPoint_test.cpp#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullPoint.h"
 #include "Coordinates.h"
 #include "RboxPoints.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "QhullPoint.h"
 #include "Qhull.h"
 
 #include 
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullPoint_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_define();
     void t_operator();
     void t_iterator();
     void t_const_iterator();
     void t_qhullpoint_iterator();
     void t_method();
     void t_io();
 };//QhullPoint_test
 
 void
 add_QhullPoint_test()
 {
     new QhullPoint_test();
 }
 
 //Executed after each test
 void QhullPoint_test::
 cleanup()
 {
     RoadTest::cleanup();
 }
 
 void QhullPoint_test::
 t_construct()
 {
     QhullPoint p12;
     QVERIFY(!p12.isDefined());
     QCOMPARE(p12.coordinates(), (coordT *)0);
     QCOMPARE(p12.dimension(), 0);
     QCOMPARE(p12.qh(), (QhullQh *)0);
     QCOMPARE(p12.id(), -3);
     QCOMPARE(p12.begin(), p12.end());
     QCOMPARE(p12.constBegin(), p12.constEnd());
 
     RboxPoints rcube("c");
     Qhull q(rcube, "Qt QR0");  // triangulation of rotated unit cube
     QhullPoint p(q);
     QVERIFY(!p.isDefined());
     QCOMPARE(p.dimension(),3);
     QCOMPARE(p.coordinates(),static_cast(0));
     QhullPoint p7(q.qh());
     QCOMPARE(p, p7);
 
     // copy constructor and copy assignment
     QhullVertex v2(q.beginVertex());
     QhullPoint p2(v2.point());
     QVERIFY(p2.isDefined());
     QCOMPARE(p2.dimension(),3);
     QVERIFY(p2!=p12);
     p= p2;  
     QCOMPARE(p, p2);
 
     QhullPoint p3(q, p2.dimension(), p2.coordinates());
     QCOMPARE(p3, p2);
     QhullPoint p8(q, p2.coordinates()); // Qhull defines dimension
     QCOMPARE(p8, p2);
     QhullPoint p9(q.qh(), p2.dimension(), p2.coordinates());
     QCOMPARE(p9, p2);
     QhullPoint p10(q.qh(), p2.coordinates()); // Qhull defines dimension
     QCOMPARE(p10, p2);
 
     Coordinates c;
     c << 0.0 << 0.0 << 0.0;
     QhullPoint p6(q, c);
     QCOMPARE(p6, q.origin());
     QhullPoint p11(q.qh(), c);
     QCOMPARE(p11, q.origin());
 
     QhullPoint p5= p2; // copy constructor
     QVERIFY(p5==p2);
     q.checkAndFreeQhullMemory();
 }//t_construct
 
 void QhullPoint_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullVertex v= q.firstVertex();
     QhullPoint p= v.point();
     std::vector vs= p.toStdVector();
     QCOMPARE(vs.size(), 3u);
     for(int k=3; k--; ){
         QCOMPARE(vs[k], p[k]);
     }
     QList qs= p.toQList();
     QCOMPARE(qs.size(), 3);
     for(int k=3; k--; ){
         QCOMPARE(qs[k], p[k]);
     }
     q.checkAndFreeQhullMemory();
 }//t_convert
 
 void QhullPoint_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullVertexList vs= q.vertexList();
         cout << "Point ids in 'rbox c'\n";
         QhullVertexListIterator i(vs);
         while(i.hasNext()){
             QhullPoint p= i.next().point();
             int id= p.id();
             cout << "p" << id << endl;
             QVERIFY(p.isDefined());
             QCOMPARE(p.dimension(),3);
             QCOMPARE(id, p.id());
             QVERIFY(p.id()>=0 && p.id()<9);
             const coordT *c= p.coordinates();
             coordT *c2= p.coordinates();
             QCOMPARE(c, c2);
             QCOMPARE(p.dimension(), 3);
             QCOMPARE(q.qh(), p.qh());
         }
         QhullPoint p2= vs.first().point();
         QhullPoint p3= vs.last().point();
         QVERIFY(p2!=p3);
         QVERIFY(p3.coordinates()!=p2.coordinates());
         q.checkAndFreeQhullMemory();
     }
 }//t_readonly
 
 void QhullPoint_test::
 t_define()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QhullVertexList vs= q.vertexList();
         QhullPoint p= vs.first().point();
         QhullPoint p2= p;
         QVERIFY(p==p2);
         QhullPoint p3= vs.last().point();
         QVERIFY(p2!=p3);
         int idx= (p3.coordinates()-p2.coordinates())/p2.dimension();
         QVERIFY(idx>-8 && idx<8);
         p2.advancePoint(idx);
         QVERIFY(p2==p3);
         p2.advancePoint(-idx);
         QVERIFY(p2==p);
         p2.advancePoint(0);
         QVERIFY(p2==p);
 
         QhullPoint p4= p3;
         QVERIFY(p4==p3);
         p4.defineAs(p2);
         QVERIFY(p2==p4);
         QhullPoint p5= p3;
         p5.defineAs(p2.dimension(), p2.coordinates());
         QVERIFY(p2==p5);
         QhullPoint p6= p3;
         p6.setCoordinates(p2.coordinates());
         QCOMPARE(p2.coordinates(), p6.coordinates());
         QVERIFY(p2==p6);
         p6.setDimension(2);
         QCOMPARE(p6.dimension(), 2);
         QVERIFY(p2!=p6);
         q.checkAndFreeQhullMemory();
     }
 }//t_define
 
 void QhullPoint_test::
 t_operator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     const QhullPoint p= q.firstVertex().point();
     //operator== and operator!= tested elsewhere
     const coordT *c= p.coordinates();
     for(int k=p.dimension(); k--; ){
         QCOMPARE(c[k], p[k]);
     }
     //p[0]= 10.0; // compiler error, const
     QhullPoint p2= q.firstVertex().point();
     p2[0]= 10.0;  // Overwrites point coordinate
     QCOMPARE(p2[0], 10.0);
     q.checkAndFreeQhullMemory();
 }//t_operator
 
 void QhullPoint_test::
 t_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullPoint p2(q);
         QCOMPARE(p2.begin(), p2.end());
 
         QhullPoint p= q.firstVertex().point();
         QhullPoint::Iterator i= p.begin();
         QhullPoint::iterator i2= p.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= p.begin();
         QVERIFY(i==i2);
         i2= p.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, p[0]);
         QCOMPARE(d2, p[2]);
         QhullPoint::Iterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), p[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         QhullPoint::ConstIterator i4= p.begin();
         QVERIFY(i==i4); // iterator COMP const_iterator
         QVERIFY(i<=i4);
         QVERIFY(i>=i4);
         QVERIFY(i4==i); // const_iterator COMP iterator
         QVERIFY(i4<=i);
         QVERIFY(i4>=i);
         QVERIFY(i>=i4);
         QVERIFY(i4<=i);
         QVERIFY(i2!=i4);
         QVERIFY(i2>i4);
         QVERIFY(i2>=i4);
         QVERIFY(i4!=i2);
         QVERIFY(i4i);
         QVERIFY(i4>=i);
 
         i= p.begin();
         i2= p.begin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, p[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, p.begin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2 += 3, p.end());
         QCOMPARE(i2 -= 3, p.begin());
         QCOMPARE(i2+0, p.begin());
         QCOMPARE(i2+3, p.end());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, p.begin());
         QCOMPARE(i2-i, 3);
 
         //p.begin end tested above
 
         // QhullPoint is const-only
         q.checkAndFreeQhullMemory();
     }
 }//t_iterator
 
 void QhullPoint_test::
 t_const_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullPoint p= q.firstVertex().point();
         QhullPoint::ConstIterator i= p.begin();
         QhullPoint::const_iterator i2= p.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= p.begin();
         QVERIFY(i==i2);
         i2= p.end();
         QVERIFY(i!=i2);
         double d3= *i;
         i2--;
         double d2= *i2;
         QCOMPARE(d3, p[0]);
         QCOMPARE(d2, p[2]);
         QhullPoint::ConstIterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3), p[1]);
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         // See t_iterator for const_iterator COMP iterator
 
         i= p.begin();
         i2= p.constBegin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, p[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, p.constBegin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2+=3, p.constEnd());
         QCOMPARE(i2-=3, p.constBegin());
         QCOMPARE(i2+0, p.constBegin());
         QCOMPARE(i2+3, p.constEnd());
         i2 += 3;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-3;
         QCOMPARE(i, p.constBegin());
         QCOMPARE(i2-i, 3);
 
         // QhullPoint is const-only
         q.checkAndFreeQhullMemory();
     }
 }//t_const_iterator
 
 void QhullPoint_test::
 t_qhullpoint_iterator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
 
     QhullPoint p2(q);
     QhullPointIterator i= p2;
     QCOMPARE(p2.dimension(), 3);
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullPoint p = q.firstVertex().point();
     QhullPointIterator i2(p);
     QCOMPARE(p.dimension(), 3);
     i= p;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     // i at front, i2 at end/back, 3 coordinates
     QCOMPARE(i.peekNext(), p[0]);
     QCOMPARE(i2.peekPrevious(), p[2]);
     QCOMPARE(i2.previous(), p[2]);
     QCOMPARE(i2.previous(), p[1]);
     QCOMPARE(i2.previous(), p[0]);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), p[0]);
     // i.peekNext()= 1.0; // compiler error, i is const
     QCOMPARE(i.next(), p[0]);
     QCOMPARE(i.peekNext(), p[1]);
     QCOMPARE(i.next(), p[1]);
     QCOMPARE(i.next(), p[2]);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p[0]);
     q.checkAndFreeQhullMemory();
 }//t_qhullpoint_iterator
 
 void QhullPoint_test::
 t_method()
 {
     // advancePoint tested above
     RboxPoints rcube("c");
     Qhull q(rcube, "");
     QhullPoint p = q.firstVertex().point();
     double dist= p.distance(q.origin());
     QCOMPARE(dist, sqrt(double(2.0+1.0))/2); // half diagonal of unit cube
     q.checkAndFreeQhullMemory();
 }//t_qhullpoint_iterator
 
 void QhullPoint_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullPoint p= q.beginVertex().point();
         ostringstream os;
         os << "Point:\n";
         os << p;
         os << "Point w/ print:\n";
         os << p.print(" message ");
         os << p.printWithIdentifier(" Point with id and a message ");
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("p"), 2);
         q.checkAndFreeQhullMemory();
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullPoint_test.moc"
diff --git a/src/qhulltest/QhullPoints_test.cpp b/src/qhulltest/QhullPoints_test.cpp
index 532451c..03ca2a3 100644
--- a/src/qhulltest/QhullPoints_test.cpp
+++ b/src/qhulltest/QhullPoints_test.cpp
@@ -1,478 +1,486 @@
 /****************************************************************************
 **
-** Copyright (p) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullPoints_test.cpp#9 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (p) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullPoints_test.cpp#10 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled header
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullPoints.h"
 #include "RboxPoints.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 
 namespace orgQhull {
 
 class QhullPoints_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_getset();
     void t_element();
     void t_iterator();
     void t_const_iterator();
     void t_search();
     void t_points_iterator();
     void t_io();
 };//QhullPoints_test
 
 void
 add_QhullPoints_test()
 {
     new QhullPoints_test();
 }
 
 //Executed after each testcase
 void QhullPoints_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullPoints_test::
 t_construct()
 {
     QhullPoints ps;
     QCOMPARE(ps.dimension(), 0);
     QVERIFY(ps.isEmpty());
     QCOMPARE(ps.count(), 0);
     QCOMPARE(ps.size(), 0u);
     QCOMPARE(ps.coordinateCount(), 0);
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps2;
     ps2.defineAs(2, 6, c);
     QCOMPARE(ps2.dimension(), 2);
     QVERIFY(!ps2.isEmpty());
     QCOMPARE(ps2.count(), 3);
     QCOMPARE(ps2.size(), 3u);
     QCOMPARE(ps2.coordinates(), c);
     QhullPoints ps7(3);
     QCOMPARE(ps7.dimension(), 3);
     QVERIFY(ps7.isEmpty());
     QhullPoints ps3(2, 6, c);
     QCOMPARE(ps3.dimension(), 2);
     QVERIFY(!ps3.isEmpty());
     QCOMPARE(ps3.coordinates(), ps2.coordinates());
     QVERIFY(ps3==ps2);
     QVERIFY(ps3!=ps);
     QhullPoints ps4= ps3;
     QVERIFY(ps4==ps3);
     // ps4= ps3; //compiler error
     QhullPoints ps5(ps4);
     QVERIFY(ps5==ps4);
     QVERIFY(!(ps5!=ps4));
     coordT c2[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps6(2, 6, c2);
     QVERIFY(ps6==ps2);
+    q.checkAndFreeQhullMemory();
 }//t_construct
 
 void QhullPoints_test::
 t_convert()
 {
     //defineAs tested above
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(3, 6, c);
     QCOMPARE(ps.dimension(), 3);
     QCOMPARE(ps.size(), 2u);
     const coordT *c2= ps.constData();
     QCOMPARE(c, c2);
     const coordT *c3= ps.data();
     QCOMPARE(c, c3);
     coordT *c4= ps.data();
     QCOMPARE(c, c4);
     std::vector vs= ps.toStdVector();
     QCOMPARE(vs.size(), 2u);
     QhullPoint p= vs[1];
     QCOMPARE(p[2], 5.0);
     QList qs= ps.toQList();
     QCOMPARE(qs.size(), 2);
     QhullPoint p2= qs[1];
     QCOMPARE(p2[2], 5.0);
+    q.checkAndFreeQhullMemory();
 }//t_convert
 
 void QhullPoints_test::
 t_getset()
 {
     //See t_construct for coordinates, count, defineAs, dimension, isempty, ==, !=, size
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(3, 6, c);
     QhullPoints ps2(3, 6, c);
     QCOMPARE(ps2.dimension(), 3);
     QCOMPARE(ps2.coordinates(), c);
     QCOMPARE(ps2.count(), 2);
     QCOMPARE(ps2.coordinateCount(), 6);
     coordT c2[]= {-1.0, -2.0, -3.0, -4.0, -5.0, -6.0};
     ps2.defineAs(6, c2);
     QCOMPARE(ps2.coordinates(), c2);
     QCOMPARE(ps2.count(), 2);
     QCOMPARE(ps2.size(), 2u);
     QCOMPARE(ps2.dimension(), 3);
     QVERIFY(!ps2.isEmpty());
     QVERIFY(ps!=ps2);
     // ps2= ps; // assignment not available, compiler error
     ps2.defineAs(ps);
     QVERIFY(ps==ps2);
     ps2.setDimension(2);
     QCOMPARE(ps2.dimension(), 2);
     QCOMPARE(ps2.coordinates(), c);
     QVERIFY(!ps2.isEmpty());
     QCOMPARE(ps2.count(), 3);
     QCOMPARE(ps2.size(), 3u);
     QVERIFY(ps!=ps2);
     QhullPoints ps3(3);
     ps3.defineAs(5, c2);
     QCOMPARE(ps3.count(), 1);
     QCOMPARE(ps3.extraCoordinatesCount(), 2);
     QCOMPARE(ps3.extraCoordinates()[0], -4.0);
     QVERIFY(ps3.includesCoordinates(ps3.data()));
     QVERIFY(ps3.includesCoordinates(ps3.data()+ps3.count()-1));
     QVERIFY(!ps3.includesCoordinates(ps3.data()-1));
     QVERIFY(!ps3.includesCoordinates(ps3.data()+ps3.coordinateCount()));
+    q.checkAndFreeQhullMemory();
 }//t_getset
 
 
 void QhullPoints_test::
 t_element()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(2, 6, c);
     QhullPoint p(2, c);
     QCOMPARE(ps[0], p);
     QCOMPARE(ps.at(1), ps[1]);
     QCOMPARE(ps.first(), p);
     QCOMPARE(ps.front(), ps.first());
     QCOMPARE(ps.last(), ps.at(2));
     QCOMPARE(ps.back(), ps.last());
     QhullPoints ps2= ps.mid(2);
     QCOMPARE(ps2.count(), 1);
     QhullPoints ps3= ps.mid(3);
     QVERIFY(ps3.isEmpty());
     QhullPoints ps4= ps.mid(10);
     QVERIFY(ps4.isEmpty());
     QhullPoints ps5= ps.mid(-1);
     QVERIFY(ps5.isEmpty());
     QhullPoints ps6= ps.mid(1, 1);
     QCOMPARE(ps6.count(), 1);
     QCOMPARE(ps6[0], ps[1]);
     QhullPoints ps7= ps.mid(1, 10);
     QCOMPARE(ps7.count(), 2);
     QCOMPARE(ps7[1], ps[2]);
     QhullPoint p8;
     QCOMPARE(ps.value(2), ps[2]);
     QCOMPARE(ps.value(-1), p8);
     QCOMPARE(ps.value(3), p8);
     QCOMPARE(ps.value(3, p), p);
     QVERIFY(ps.value(1, p)!=p);
     foreach(QhullPoint p9, ps){  // Qt only
         QCOMPARE(p9.dimension(), 2);
         QVERIFY(p9[0]==0.0 || p9[0]==2.0 || p9[0]==4.0);
     }
+    q.checkAndFreeQhullMemory();
 }//t_element
 
 void QhullPoints_test::
 t_iterator()
 {
     coordT c[]= {0.0, 1.0, 2.0};
     QhullPoints ps(1, 3, c);
     QhullPoints::Iterator i(ps);
     QhullPoints::iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p(i); // QhullPoint is the base class for QhullPoints::iterator
     QCOMPARE(p.dimension(), ps.dimension());
     QCOMPARE(p.coordinates(), ps.coordinates());
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p[0], 0.0);
     QCOMPARE(p2[0], 2.0);
     QhullPoints::Iterator i5(i2);
     QCOMPARE(*i2, *i5);
     coordT c3[]= {0.0, -1.0, -2.0};
     QhullPoints::Iterator i3(1, c3);
     QVERIFY(i!=i3);
     QCOMPARE(*i, *i3);
 
     (i3= i)++;
     QCOMPARE((*i3)[0], 1.0);
     QCOMPARE(i3->dimension(), 1);
     QCOMPARE(i3[0][0], 1.0);
     QCOMPARE(i3[0], ps[1]);
 
     QVERIFY(i==i);
     QVERIFY(i!=i2);
     QVERIFY(ii);
     QVERIFY(i2>=i);
 
     QhullPoints::ConstIterator i4(1, c);
     QVERIFY(i==i4); // iterator COMP const_iterator
     QVERIFY(i<=i4);
     QVERIFY(i>=i4);
     QVERIFY(i4==i); // const_iterator COMP iterator
     QVERIFY(i4<=i);
     QVERIFY(i4>=i);
     QVERIFY(i>=i4);
     QVERIFY(i4<=i);
     QVERIFY(i2!=i4);
     QVERIFY(i2>i4);
     QVERIFY(i2>=i4);
     QVERIFY(i4!=i2);
     QVERIFY(i4i);
     QVERIFY(i4>=i);
 
     i= ps.begin();
     i2= ps.begin();
     QCOMPARE(i, i2++);
     QCOMPARE(*i2, ps[1]);
     QCOMPARE(++i, i2);
     QCOMPARE(i, i2--);
     QCOMPARE(i2, ps.begin());
     QCOMPARE(--i, i2);
     QCOMPARE(i2+=3, ps.end());
     QCOMPARE(i2-=3, ps.begin());
     QCOMPARE(i2+0, ps.begin());
     QCOMPARE(i2+3, ps.end());
     i2 += 3;
     i= i2-0;
     QCOMPARE(i, i2);
     i= i2-3;
     QCOMPARE(i, ps.begin());
     QCOMPARE(i2-i, 3);
 
     //ps.begin end tested above
 
     // QhullPoints is const-only
+    q.checkAndFreeQhullMemory();
 }//t_iterator
 
 void QhullPoints_test::
 t_const_iterator()
 {
     coordT c[]= {0.0, 1.0, 2.0};
     const QhullPoints ps(1, 3, c);
     QhullPoints::ConstIterator i(ps);
     QhullPoints::const_iterator i2= ps.begin();
     QVERIFY(i==i2);
     QVERIFY(i>=i2);
     QVERIFY(i<=i2);
     i= ps.begin();
     QVERIFY(i==i2);
     i2= ps.end();
     QVERIFY(i!=i2);
     QhullPoint p(i);
     QCOMPARE(p.dimension(), ps.dimension());
     QCOMPARE(p.coordinates(), ps.coordinates());
     i2--;
     QhullPoint p2= *i2;
     QCOMPARE(p[0], 0.0);
     QCOMPARE(p2[0], 2.0);
     QhullPoints::ConstIterator i5(i2);
     QCOMPARE(*i2, *i5);
     coordT c3[]= {0.0, -1.0, -2.0};
     QhullPoints::ConstIterator i3(1, c3);
     QVERIFY(i!=i3);
     QCOMPARE(*i, *i3);
 
     (i3= i)++;
     QCOMPARE((*i3)[0], 1.0);
     QCOMPARE(i3->dimension(), 1);
     QCOMPARE(i3[0][0], 1.0);
     QCOMPARE(i3[0][0], 1.0);
     QCOMPARE(i3[0], ps[1]);
 
     QVERIFY(i==i);
     QVERIFY(i!=i2);
     QVERIFY(ii);
     QVERIFY(i2>=i);
 
     // See t_iterator for const_iterator COMP iterator
 
     i= ps.begin();
     i2= ps.constBegin();
     QCOMPARE(i, i2++);
     QCOMPARE(*i2, ps[1]);
     QCOMPARE(++i, i2);
     QCOMPARE(i, i2--);
     QCOMPARE(i2, ps.constBegin());
     QCOMPARE(--i, i2);
     QCOMPARE(i2+=3, ps.constEnd());
     QCOMPARE(i2-=3, ps.constBegin());
     QCOMPARE(i2+0, ps.constBegin());
     QCOMPARE(i2+3, ps.constEnd());
     i2 += 3;
     i= i2-0;
     QCOMPARE(i, i2);
     i= i2-3;
     QCOMPARE(i, ps.constBegin());
     QCOMPARE(i2-i, 3);
 
     // QhullPoints is const-only
+    q.checkAndFreeQhullMemory();
 }//t_const_iterator
 
 
 void QhullPoints_test::
 t_search()
 {
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0, 1};
     QhullPoints ps(2, 8, c); //2-d array of 4 points
     QhullPoint p= ps.first();
     QhullPoint p2= ps.last();
     QVERIFY(ps.contains(p));
     QVERIFY(ps.contains(p2));
     QVERIFY(p==p2);
     QhullPoint p5= ps[2];
     QVERIFY(p!=p5);
     QVERIFY(ps.contains(p5));
     coordT c2[]= {0.0, 1.0, 2.0, 3.0};
     QhullPoint p3(2, c2); //2-d point
     QVERIFY(ps.contains(p3));
     QhullPoint p4(3, c2); //3-d point
     QVERIFY(!ps.contains(p4));
     p4.defineAs(2, c); //2-d point
     QVERIFY(ps.contains(p4));
     p4.defineAs(2, c+1); //2-d point
     QVERIFY(!ps.contains(p4));
     QhullPoint p6(2, c2+2); //2-d point
     QCOMPARE(ps.count(p), 2);
     QCOMPARE(ps.count(p2), 2);
     QCOMPARE(ps.count(p3), 2);
     QCOMPARE(ps.count(p4), 0);
     QCOMPARE(ps.count(p6), 1);
     QCOMPARE(ps.indexOf(&ps[0][0]), 0);
     //QCOMPARE(ps.indexOf(ps.end()), -1); //ps.end() is a QhullPoint which may match
     QCOMPARE(ps.indexOf(0), -1);
     QCOMPARE(ps.indexOf(&ps[3][0]), 3);
     QCOMPARE(ps.indexOf(&ps[3][1], QhullError::NOthrow), 3);
     QCOMPARE(ps.indexOf(ps.data()+ps.coordinateCount(), QhullError::NOthrow), -1);
     QCOMPARE(ps.indexOf(p), 0);
     QCOMPARE(ps.indexOf(p2), 0);
     QCOMPARE(ps.indexOf(p3), 0);
     QCOMPARE(ps.indexOf(p4), -1);
     QCOMPARE(ps.indexOf(p5), 2);
     QCOMPARE(ps.indexOf(p6), 1);
     QCOMPARE(ps.lastIndexOf(p), 3);
     QCOMPARE(ps.lastIndexOf(p4), -1);
     QCOMPARE(ps.lastIndexOf(p6), 1);
     QhullPoints ps2(3);
     QCOMPARE(ps2.indexOf(ps2.data()), -1);
     QCOMPARE(ps2.indexOf(ps2.data()+1, QhullError::NOthrow), -1);
     QCOMPARE(ps2.indexOf(p), -1);
     QCOMPARE(ps2.lastIndexOf(p), -1);
     QhullPoints ps3;
     QCOMPARE(ps3.indexOf(ps3.data()), -1);
     QCOMPARE(ps3.indexOf(ps3.data()+1, QhullError::NOthrow), -1);
     QCOMPARE(ps3.indexOf(p), -1);
     QCOMPARE(ps3.lastIndexOf(p), -1);
     QhullPoints ps4(2, 0, c);
     QCOMPARE(ps4.indexOf(p), -1);
     QCOMPARE(ps4.lastIndexOf(p), -1);
+    q.checkAndFreeQhullMemory();
 }//t_search
 
 void QhullPoints_test::
 t_points_iterator()
 {
     coordT c2[]= {0.0};
     QhullPoints ps2(0, 0, c2); // 0-dimensional
     QhullPointsIterator i2= ps2;
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     i2.toBack();
     QVERIFY(!i2.hasNext());
     QVERIFY(!i2.hasPrevious());
 
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps(3, 6, c); // 3-dimensional
     QhullPointsIterator i(ps);
     i2= ps;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullPoint p= ps[0];
     QhullPoint p2(ps[0]);
     QCOMPARE(p, p2);
     QVERIFY(p==p2);
     QhullPoint p3(ps[1]);
  // p2[0]= 0.0;
     QVERIFY(p==p2);
     QCOMPARE(i2.peekPrevious(), p3);
     QCOMPARE(i2.previous(), p3);
     QCOMPARE(i2.previous(), p);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), p);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), p);
     QCOMPARE(i.peekNext(), p3);
     QCOMPARE(i.next(), p3);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), p);
+    q.checkAndFreeQhullMemory();
 }//t_points_iterator
 
 void QhullPoints_test::
 t_io()
 {
     QhullPoints ps;
     ostringstream os;
     os << "Empty QhullPoints\n" << ps << endl;
     coordT c[]= {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
     QhullPoints ps2(3, 6, c); // 3-dimensional explicit
     os << "QhullPoints from c[]\n" << ps2 << endl;
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullPoints ps3= q.points();
     os << "QhullPoints\n" << ps3;
     os << "RunId\n" << ps3.print();
     os << ps3.print("RunId w/ message\n");
     os << ps3.printWithIdentifier("RunId w/ identifiers\n");
     cout << os.str();
     QString s= QString::fromStdString(os.str());
     QCOMPARE(s.count("p"), 3*8+3);
     // QCOMPARE(s.count(QRegExp("f\\d")), 3*7 + 13*3*2);
+    q.checkAndFreeQhullMemory();
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullPoints_test.moc"
diff --git a/src/qhulltest/QhullRidge_test.cpp b/src/qhulltest/QhullRidge_test.cpp
index 70e68ed..944dcf4 100644
--- a/src/qhulltest/QhullRidge_test.cpp
+++ b/src/qhulltest/QhullRidge_test.cpp
@@ -1,163 +1,166 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullRidge_test.cpp#7 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullRidge_test.cpp#8 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullRidge.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullRidge_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_getSet();
     void t_foreach();
     void t_io();
 };//QhullRidge_test
 
 void
 add_QhullRidge_test()
 {
     new QhullRidge_test();
 }
 
 //Executed after each testcase
 void QhullRidge_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullRidge_test::
 t_construct()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullRidge r;
     QVERIFY(!r.isDefined());
     QCOMPARE(r.dimension(),0);
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
     QhullFacet f(q.firstFacet());
     QhullRidgeSet rs(f.ridges());
     QVERIFY(!rs.isEmpty()); // Simplicial facets do not have ridges()
     QhullRidge r2(rs.first());
     QCOMPARE(r2.dimension(), 2); // One dimension lower than the facet
     r= r2;
     QVERIFY(r.isDefined());
     QCOMPARE(r.dimension(), 2);
     QhullRidge r3= r2.getRidgeT();
     QCOMPARE(r,r3);
     QhullRidge r4= r2.getBaseT();
     QCOMPARE(r,r4);
     QhullRidge r5= r2; // copy constructor
     QVERIFY(r5==r2);
     QVERIFY(r5==r);
+    q.checkAndFreeQhullMemory();
 }//t_construct
 
 void QhullRidge_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 6);
         QCOMPARE(q.vertexCount(), 8);
         QhullFacet f(q.firstFacet());
         QhullRidgeSet rs= f.ridges();
         QhullRidgeSetIterator i(rs);
         while(i.hasNext()){
             const QhullRidge r= i.next();
             cout << r.id() << endl;
             QVERIFY(r.bottomFacet()!=r.topFacet());
             QCOMPARE(r.dimension(), 2); // Ridge one-dimension less than facet
             QVERIFY(r.id()>=0 && r.id()<9*27);
             QVERIFY(r.isDefined());
             QVERIFY(r==r);
             QVERIFY(r==i.peekPrevious());
             QCOMPARE(r.otherFacet(r.bottomFacet()),r.topFacet());
             QCOMPARE(r.otherFacet(r.topFacet()),r.bottomFacet());
         }
         QhullRidgeSetIterator i2(i);
         QEXPECT_FAIL("", "SetIterator copy constructor not reset to BOT", Continue);
         QVERIFY(!i2.hasPrevious());
+        q.checkAndFreeQhullMemory();
     }
 }//t_getSet
 
 void QhullRidge_test::
 t_foreach()
 {
     RboxPoints rcube("c");  // cube
     {
         Qhull q(rcube, "QR0"); // rotated cube
         QhullFacet f(q.firstFacet());
         foreach (QhullRidge r, f.ridges()){  // Qt only
             QhullVertexSet vs= r.vertices();
             QCOMPARE(vs.count(), 2);
             foreach (QhullVertex v, vs){  // Qt only
                 QVERIFY(f.vertices().contains(v));
             }
         }
         QhullRidgeSet rs= f.ridges();
         QhullRidge r= rs.first();
         QhullRidge r2= r;
         QList vs;
         int count= 0;
         while(!count || r2!=r){
             ++count;
             QhullVertex v;
             QVERIFY2(r2.hasNextRidge3d(f),"A cube should only have non-simplicial facets.");
             QhullRidge r3= r2.nextRidge3d(f, &v);
             QVERIFY(!vs.contains(v));
             vs << v;
             r2= r2.nextRidge3d(f);
             QCOMPARE(r3, r2);
         }
         QCOMPARE(vs.count(), rs.count());
         QCOMPARE(count, rs.count());
+        q.checkAndFreeQhullMemory();
     }
 }//t_foreach
 
 void QhullRidge_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullFacet f(q.firstFacet());
         QhullRidgeSet rs= f.ridges();
         QhullRidge r= rs.first();
         ostringstream os;
         os << "Ridges\n" << rs << "Ridge\n" << r;
         os << "Ridge with runId FIXUP\n" << r.print();
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count(" r"), 6+2);
+        q.checkAndFreeQhullMemory();
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullRidge_test.moc"
diff --git a/src/qhulltest/QhullSet_test.cpp b/src/qhulltest/QhullSet_test.cpp
index f328c3a..227bd5d 100644
--- a/src/qhulltest/QhullSet_test.cpp
+++ b/src/qhulltest/QhullSet_test.cpp
@@ -1,432 +1,439 @@
 /****************************************************************************
 **
-** Copyright (c) 2009-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullSet_test.cpp#6 $$Change: 1708 $
-** $DateTime: 2014/03/26 19:13:56 $$Author: bbarber $
+** Copyright (c) 2009-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullSet_test.cpp#7 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "QhullRidge.h"
 #include "QhullFacetSet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 
 namespace orgQhull {
 
 class QhullSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_qhullsetbase();
     void t_convert();
     void t_element();
     void t_search();
     void t_iterator();
     void t_const_iterator();
     void t_qhullset_iterator();
     void t_io();
 };//QhullSet_test
 
 void
 add_QhullSet_test()
 {
     new QhullSet_test();
 }
 
 //Executed after each testcase
 void QhullSet_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 // Test QhullFacetSet and QhullSet.
 // Use QhullRidgeSet to test methods overloaded by QhullFacetSet
 
 void QhullSet_test::
 t_qhullsetbase()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // triangulation of rotated unit cube
         // Fake an empty set.  Default constructor not defined.  No memory allocation.
         QhullFacet f4 = q.beginFacet();
         QhullFacetSet fs = f4.neighborFacets();
         fs.defineAs(q.qhullQh()->other_points); // Force an empty set
         QVERIFY(fs.isEmpty());
         QCOMPARE(fs.count(), 0);
         QCOMPARE(fs.size(), 0u);
         QCOMPARE(fs.begin(), fs.end()); // beginPointer(), endPointer()
         QVERIFY(QhullSetBase::isEmpty(fs.getSetT()));
 
         QhullRidgeSet rs = f4.ridges();
         QVERIFY(!rs.isEmpty());
         QCOMPARE(rs.count(), 4);
         QCOMPARE(rs.size(), 4u);
         QVERIFY(rs.begin()!=rs.end());
         QVERIFY(!QhullSetBase::isEmpty(rs.getSetT()));
         QhullRidgeSet rs2= rs; // copy constructor
         // rs= rs2; // disabled.  Would not copy ridges
         QCOMPARE(rs2, rs);
 
         QCOMPARE(q.facetCount(), 6);
         QhullFacet f = q.beginFacet();
         QhullFacetSet fs2 = f.neighborFacets();
         QCOMPARE(fs2.count(), 4);
         QCOMPARE(fs2.size(), 4u);
         QVERIFY(!fs2.isEmpty());
         QVERIFY(!QhullSetBase::isEmpty(fs2.getSetT()));
         QVERIFY(fs!=fs2);
         setT *s= fs2.getSetT();
         fs.defineAs(s);
         QVERIFY(fs==fs2);
         QCOMPARE(fs[1], fs2[1]); // elementPointer
         QhullFacetSet fs3(fs2);
         QVERIFY(fs3==fs);
         // fs= fs2; // disabled.  Would not copy facets
         QhullFacetSet fs4= fs2; // copy constructor
         QVERIFY(fs4==fs2);
+        q.checkAndFreeQhullMemory();
     }
 }//t_qhullsetbase
 
 // constructors tested by t_qhullsetbase
 
 void QhullSet_test::
 t_convert()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullFacet f= q.firstFacet();
         f= f.next();
         QhullRidgeSet rs= f.ridges();
         QCOMPARE(rs.count(),4);
         std::vector rv= rs.toStdVector();
         QCOMPARE(rv.size(), 4u);
         QList rv2= rs.toQList();
         QCOMPARE(rv2.size(), 4);
         std::vector::iterator i= rv.begin();
         foreach(QhullRidge r, rv2){  // Qt only
             QhullRidge r2= *i++;
             QCOMPARE(r, r2);
         }
 
         Qhull q2(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q2.facetCount(), 12);
         QhullFacet f2 = q2.beginFacet();
         QhullFacetSet fs = f2.neighborFacets();
         QCOMPARE(fs.size(), 3U);
         std::vector vs= fs.toStdVector();
         QCOMPARE(vs.size(), fs.size());
         for(int k= fs.count(); k--; ){
             QCOMPARE(vs[k], fs[k]);
         }
         QList qv= fs.toQList();
         QCOMPARE(qv.count(), fs.count());
         for(int k= fs.count(); k--; ){
             QCOMPARE(qv[k], fs[k]);
         }
+        q.checkAndFreeQhullMemory();
     }
 }//t_convert
 
 //ReadOnly (count, isEmpty) tested by t_convert
 //  operator== tested by t_search
 
 void QhullSet_test::
 t_element()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f = q.beginFacet();
     QhullFacetSet fs = f.neighborFacets();
 
     QCOMPARE(fs.at(1), fs[1]);
     QCOMPARE(fs.first(), fs[0]);
     QCOMPARE(fs.front(), fs.first());
     QCOMPARE(fs.last(), fs.at(3));
     QCOMPARE(fs.back(), fs.last());
     QhullFacet *d= fs.data();
     const QhullFacet *d2= fs.data();
     const QhullFacet *d3= fs.constData();
     QVERIFY(d==d2);
     QVERIFY(d2==d3);
     QCOMPARE(*d, fs.first());
     QCOMPARE(d+4, fs.end());
     QCOMPARE((d+4)->getFacetT(), static_cast(0));
     QhullFacet f4= *(d+4);
     QVERIFY(!f4.isDefined());
     QCOMPARE(fs.second(), fs[1]);
     const QhullFacet f2= fs.second();
     QVERIFY(f2==fs[1]);
     const QhullFacet f3= fs[1];
     QCOMPARE(f2, f3);
 
     QCOMPARE(fs.value(2), fs[2]);
     QCOMPARE(fs.value(-1), QhullFacet());
     QCOMPARE(fs.value(10), QhullFacet());
     QCOMPARE(fs.value(2, f), fs[2]);
     QCOMPARE(fs.value(4, f), f);
     // mid() not available (read-only)
+    q.checkAndFreeQhullMemory();
 }//t_element
 
 void QhullSet_test::
 t_search()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f = q.beginFacet();
     QhullFacetSet fs = f.neighborFacets();
     QhullFacet f2= *fs.begin();
     QhullFacet f3= fs.last();
     QVERIFY(fs.contains(f2));
     QVERIFY(fs.contains(f3));
     QVERIFY(!fs.contains(f));
 
     QhullFacetSet fs2= f2.neighborFacets();
     QVERIFY(fs==fs);
     QVERIFY(fs!=fs2);
     QCOMPARE(fs.count(f2), 1);
     QCOMPARE(fs.count(f3), 1);
     QCOMPARE(fs.count(f), 0);
     QCOMPARE(fs.indexOf(f2), 0);
     QCOMPARE(fs.indexOf(f3), 3);
     QCOMPARE(fs.indexOf(f), -1);
     QCOMPARE(fs.lastIndexOf(f2), 0);
     QCOMPARE(fs.lastIndexOf(f3), 3);
     QCOMPARE(fs.lastIndexOf(f), -1);
+    q.checkAndFreeQhullMemory();
 }//t_search
 
 void QhullSet_test::
 t_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullFacet f = q.beginFacet();
         QhullFacetSet fs = f.neighborFacets();
         QhullFacetSet::Iterator i= fs.begin();
         QhullFacetSet::iterator i2= fs.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= fs.begin();
         QVERIFY(i==i2);
         i2= fs.end();
         QVERIFY(i!=i2);
         QhullFacet f3(*i);
         i2--;
         QhullFacet f2= *i2;
         QCOMPARE(f3.id(), fs[0].id());
         QCOMPARE(f2.id(), fs[3].id());
         QhullFacetSet::Iterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3).id(), fs[1].id());
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         QhullFacetSet::ConstIterator i4= fs.begin();
         QVERIFY(i==i4); // iterator COMP const_iterator
         QVERIFY(i<=i4);
         QVERIFY(i>=i4);
         QVERIFY(i4==i); // const_iterator COMP iterator
         QVERIFY(i4<=i);
         QVERIFY(i4>=i);
         QVERIFY(i>=i4);
         QVERIFY(i4<=i);
         QVERIFY(i2!=i4);
         QVERIFY(i2>i4);
         QVERIFY(i2>=i4);
         QVERIFY(i4!=i2);
         QVERIFY(i4i);
         QVERIFY(i4>=i);
 
         i= fs.begin();
         i2= fs.begin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, fs[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, fs.begin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2 += 4, fs.end());
         QCOMPARE(i2 -= 4, fs.begin());
         QCOMPARE(i2+0, fs.begin());
         QCOMPARE(i2+4, fs.end());
         i2 += 4;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-4;
         QCOMPARE(i, fs.begin());
         QCOMPARE(i2-i, 4);
 
         //fs.begin end tested above
 
         // QhullFacetSet is const-only
+        q.checkAndFreeQhullMemory();
     }
 }//t_iterator
 
 void QhullSet_test::
 t_const_iterator()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0");  // rotated unit cube
         QhullFacet f = q.beginFacet();
         QhullFacetSet fs = f.neighborFacets();
         QhullFacetSet::ConstIterator i= fs.begin();
         QhullFacetSet::const_iterator i2= fs.begin();
         QVERIFY(i==i2);
         QVERIFY(i>=i2);
         QVERIFY(i<=i2);
         i= fs.begin();
         QVERIFY(i==i2);
         i2= fs.end();
         QVERIFY(i!=i2);
         QhullFacet f3(*i);
         i2--;
         QhullFacet f2= *i2;
         QCOMPARE(f3.id(), fs[0].id());
         QCOMPARE(f2.id(), fs[3].id());
         QhullFacetSet::ConstIterator i3(i2);
         QCOMPARE(*i2, *i3);
 
         (i3= i)++;
         QCOMPARE((*i3).id(), fs[1].id());
         QVERIFY(i==i);
         QVERIFY(i!=i2);
         QVERIFY(ii);
         QVERIFY(i2>=i);
 
         // See t_iterator for const_iterator COMP iterator
 
         i= fs.begin();
         i2= fs.constBegin();
         QCOMPARE(i, i2++);
         QCOMPARE(*i2, fs[1]);
         QCOMPARE(++i, i2);
         QCOMPARE(i, i2--);
         QCOMPARE(i2, fs.constBegin());
         QCOMPARE(--i, i2);
         QCOMPARE(i2+=4, fs.constEnd());
         QCOMPARE(i2-=4, fs.constBegin());
         QCOMPARE(i2+0, fs.constBegin());
         QCOMPARE(i2+4, fs.constEnd());
         i2 += 4;
         i= i2-0;
         QCOMPARE(i, i2);
         i= i2-4;
         QCOMPARE(i, fs.constBegin());
         QCOMPARE(i2-i, 4);
 
         // QhullFacetSet is const-only
+        q.checkAndFreeQhullMemory();
     }
 }//t_const_iterator
 
 void QhullSet_test::
 t_qhullset_iterator()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     // Fake an empty set.  Default constructor not defined.  No memory allocation.
     QhullFacet f = q.beginFacet();
     QhullFacetSet fs = f.neighborFacets();
     fs.defineAs(q.qhullQh()->other_points);
     QhullFacetSetIterator i= fs;
     QCOMPARE(fs.count(), 0);
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
     i.toBack();
     QVERIFY(!i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     QhullFacet f2 = q.beginFacet();
     QhullFacetSet fs2 = f2.neighborFacets();
     QhullFacetSetIterator i2(fs2);
     QCOMPARE(fs2.count(), 4);
     i= fs2;
     QVERIFY(i2.hasNext());
     QVERIFY(!i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
     i2.toBack();
     i.toFront();
     QVERIFY(!i2.hasNext());
     QVERIFY(i2.hasPrevious());
     QVERIFY(i.hasNext());
     QVERIFY(!i.hasPrevious());
 
     // i at front, i2 at end/back, 4 neighbors
     QhullFacetSet fs3 = f2.neighborFacets(); // same as fs2
     QhullFacet f3(fs2[0]);
     QhullFacet f4= fs3[0];
     QCOMPARE(f3, f4);
     QVERIFY(f3==f4);
     QhullFacet f5(fs3[1]);
     QVERIFY(f4!=f5);
     QhullFacet f6(fs3[2]);
     QhullFacet f7(fs3[3]);
     QCOMPARE(i2.peekPrevious(), f7);
     QCOMPARE(i2.previous(), f7);
     QCOMPARE(i2.previous(), f6);
     QCOMPARE(i2.previous(), f5);
     QCOMPARE(i2.previous(), f4);
     QVERIFY(!i2.hasPrevious());
     QCOMPARE(i.peekNext(), f4);
     // i.peekNext()= 1.0; // compiler error
     QCOMPARE(i.next(), f4);
     QCOMPARE(i.peekNext(), f5);
     QCOMPARE(i.next(), f5);
     QCOMPARE(i.next(), f6);
     QCOMPARE(i.next(), f7);
     QVERIFY(!i.hasNext());
     i.toFront();
     QCOMPARE(i.next(), f4);
+    q.checkAndFreeQhullMemory();
 }//t_qhullset_iterator
 
 void QhullSet_test::
 t_io()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     // Fake an empty set.  Default constructor not defined.  No memory allocation.
     QhullFacet f= q.beginFacet();
     QhullFacetSet fs= f.neighborFacets();
     fs.defineAs(q.qhullQh()->other_points);
     cout << "INFO:     empty set" << fs << std::endl;
     QhullFacet f2= q.beginFacet();
     QhullFacetSet fs2= f2.neighborFacets();
     cout << "INFO:   Neighboring facets\n";
     cout << fs2 << std::endl;
 
     QhullRidgeSet rs= f.ridges();
     cout << "INFO:   Ridges for a facet\n";
     cout << rs << std::endl;
+    q.checkAndFreeQhullMemory();
 }//t_io
 
 }//namespace orgQhull
 
 #include "moc/QhullSet_test.moc"
diff --git a/src/qhulltest/QhullVertexSet_test.cpp b/src/qhulltest/QhullVertexSet_test.cpp
index d417e62..99bb49b 100644
--- a/src/qhulltest/QhullVertexSet_test.cpp
+++ b/src/qhulltest/QhullVertexSet_test.cpp
@@ -1,185 +1,185 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2012 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullVertexSet_test.cpp#3 $$Change: 1464 $
-** $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullVertexSet_test.cpp#4 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #include 
 #include "../road/RoadTest.h" // FIXUP First for QHULL_USES_QT
 
 #include "Qhull.h"
 #include "QhullError.h"
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullFacetSet_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_convert();
     void t_readonly();
     void t_foreach();
     void t_io();
 };//QhullFacetSet_test
 
 void
 add_QhullFacetSet_test()
 {
     new QhullFacetSet_test();
 }
 
 //Executed after each testcase
 void QhullFacetSet_test::
 cleanup()
 {
     RoadTest::cleanup();
     UsingQhullLib::checkQhullMemoryEmpty();
 }
 
 void QhullFacetSet_test::
 t_construct()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullFacetSet fs2= f.neighborFacets();
     QVERIFY(!fs2.isEmpty());
     QCOMPARE(fs2.count(),4);
     QhullFacetSet fs4= fs2; // copy constructor
     QVERIFY(fs4==fs2);
     QhullFacetSet fs3(q.qhullQh()->facet_mergeset);
     QVERIFY(fs3.isEmpty());
 }//t_construct
 
 void QhullFacetSet_test::
 t_convert()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QR0 QV2");  // rotated unit cube
     QhullFacet f= q.firstFacet();
     QhullFacetSet fs2= f.neighborFacets();
     QVERIFY(!fs2.isSelectAll());
     QCOMPARE(fs2.count(),2);
     std::vector fv= fs2.toStdVector();
     QCOMPARE(fv.size(), 2u);
     QList fv2= fs2.toQList();
     QCOMPARE(fv2.size(), 2);
     fs2.selectAll();
     QVERIFY(fs2.isSelectAll());
     std::vector fv3= fs2.toStdVector();
     QCOMPARE(fv3.size(), 4u);
     QList fv4= fs2.toQList();
     QCOMPARE(fv4.size(), 4);
 }//t_convert
 
 //! Spot check properties and read-only.  See QhullSet_test
 void QhullFacetSet_test::
 t_readonly()
 {
     RboxPoints rcube("c");
     Qhull q(rcube,"QV0");  // good facets are adjacent to point 0
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     fs.selectAll();
     QVERIFY(fs.isSelectAll());
     QCOMPARE(fs.count(), 4);
     fs.selectGood();
     QVERIFY(!fs.isSelectAll());
     QCOMPARE(fs.count(), 2);
     QhullFacet f= fs.first();
     QhullFacet f2= fs.last();
     fs.selectAll();
     QVERIFY(fs.contains(f));
     QVERIFY(fs.contains(f2));
     QVERIFY(f.isGood());
     QVERIFY(!f2.isGood());
     fs.selectGood();
     QVERIFY(fs.contains(f));
     QVERIFY(!fs.contains(f2));
 }//t_readonly
 
 void QhullFacetSet_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     // Spot check predicates and accessors.  See QhullLinkedList_test
     Qhull q(rcube,"QR0");  // rotated unit cube
     QhullFacetSet fs= q.firstFacet().neighborFacets();
     QVERIFY(!fs.contains(q.firstFacet()));
     QVERIFY(fs.contains(fs.first()));
     QhullFacet f= q.firstFacet().next();
     if(!fs.contains(f)){
         f= f.next();
     }
     QVERIFY(fs.contains(f));
     QCOMPARE(fs.first(), *fs.begin());
     QCOMPARE(*(fs.end()-1), fs.last());
 }//t_foreach
 
 void QhullFacetSet_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"QR0 QV0");   // good facets are adjacent to point 0
         QhullFacetSet fs= q.firstFacet().neighborFacets();
         ostringstream os;
         os << fs.print(q.runId(), "Neighbors of first facet with point 0");
         os << fs.printIdentifiers("\nFacet identifiers: ");
         cout<< os.str();
         QString facets= QString::fromStdString(os.str());
         QCOMPARE(facets.count(QRegExp(" f[0-9]")), 2+13*2);
     }
 }//t_io
 
 //FIXUP -- Move conditional, QhullFacetSet code to QhullFacetSet.cpp
 #ifndef QHULL_NO_STL
 std::vector QhullFacetSet::
 toStdVector() const
 {
     QhullSetIterator i(*this);
     std::vector vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.push_back(f);
         }
     }
     return vs;
 }//toStdVector
 #endif //QHULL_NO_STL
 
 #ifdef QHULL_USES_QT
 QList QhullFacetSet::
 toQList() const
 {
     QhullSetIterator i(*this);
     QList vs;
     while(i.hasNext()){
         QhullFacet f= i.next();
         if(isSelectAll() || f.isGood()){
             vs.append(f);
         }
     }
     return vs;
 }//toQList
 #endif //QHULL_USES_QT
 
 }//orgQhull
 
 #include "moc/QhullFacetSet_test.moc"
diff --git a/src/qhulltest/QhullVertex_test.cpp b/src/qhulltest/QhullVertex_test.cpp
index c807f6e..019def9 100644
--- a/src/qhulltest/QhullVertex_test.cpp
+++ b/src/qhulltest/QhullVertex_test.cpp
@@ -1,184 +1,188 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/QhullVertex_test.cpp#8 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/QhullVertex_test.cpp#9 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 //pre-compiled headers
 #include 
 #include "RoadTest.h"
 
 #include "QhullVertex.h"
 #include "Coordinates.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacet.h"
 #include "QhullFacetSet.h"
 #include "QhullVertexSet.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::ostream;
 using std::string;
 
 namespace orgQhull {
 
 class QhullVertex_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_constructConvert();
     void t_getSet();
     void t_foreach();
     void t_io();
 };//QhullVertex_test
 
 void
 add_QhullVertex_test()
 {
     new QhullVertex_test();
 }
 
 //Executed after each testcase
 void QhullVertex_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void QhullVertex_test::
 t_constructConvert()
 {
     // Qhull.runQhull() constructs QhullFacets as facetT
     QhullVertex v;
     QVERIFY(!v.isDefined());
     QCOMPARE(v.dimension(),0);
     RboxPoints rcube("c");
     Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
     QhullVertex v2(q.beginVertex());
     QCOMPARE(v2.dimension(),3);
     v= v2;  // copy assignment
     QVERIFY(v.isDefined());
     QCOMPARE(v.dimension(),3);
     QhullVertex v5= v2; // copy constructor
     QVERIFY(v5==v2);
     QVERIFY(v5==v);
     QhullVertex v3= v2.getVertexT();
     QCOMPARE(v,v3);
     QhullVertex v4= v2.getBaseT();
     QCOMPARE(v,v4);
+    q.checkAndFreeQhullMemory();
 }//t_constructConvert
 
 void QhullVertex_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube,"Qt QR0");  // triangulation of rotated unit cube
         QCOMPARE(q.facetCount(), 12);
         QCOMPARE(q.vertexCount(), 8);
 
         // Also spot-test QhullVertexList.  See QhullLinkedList_test.cpp
         QhullVertexList vs= q.vertexList();
         QhullVertexListIterator i(vs);
         while(i.hasNext()){
             const QhullVertex v= i.next();
             cout << v.id() << endl;
             QCOMPARE(v.dimension(),3);
             QVERIFY(v.id()>=0 && v.id()<9);
             QVERIFY(v.isDefined());
             if(i.hasNext()){
                 QCOMPARE(v.next(), i.peekNext());
                 QVERIFY(v.next()!=v);
                 QVERIFY(v.next().previous()==v);
             }
             QVERIFY(i.hasPrevious());
             QCOMPARE(v, i.peekPrevious());
         }
         QhullVertexListIterator i2(i);
         QEXPECT_FAIL("", "ListIterator copy constructor not reset to BOT", Continue);
         QVERIFY(!i2.hasPrevious());
 
         // test point()
         foreach (QhullVertex v, q.vertexList()){  // Qt only
             QhullPoint p= v.point();
             int j= p.id();
             cout << "Point " << j << ":\n" << p.print() << endl;
             QVERIFY(j>=0 && j<8);
         }
+        q.checkAndFreeQhullMemory();
     }
 }//t_getSet
 
 void QhullVertex_test::
 t_foreach()
 {
     RboxPoints rcube("c W0 300");  // 300 points on surface of cube
     {
         Qhull q(rcube, "QR0 Qc"); // keep coplanars, thick facet, and rotate the cube
         foreach (QhullVertex v, q.vertexList()){  // Qt only
             QhullFacetSet fs= v.neighborFacets();
             QCOMPARE(fs.count(), 3);
             foreach (QhullFacet f, fs){  // Qt only
                 QVERIFY(f.vertices().contains(v));
             }
         }
+        q.checkAndFreeQhullMemory();
     }
 }//t_foreach
 
 void QhullVertex_test::
 t_io()
 {
     RboxPoints rcube("c");
     {
         Qhull q(rcube, "");
         QhullVertex v= q.beginVertex();
         ostringstream os;
         os << "Vertex and vertices w/o runId:\n";
         os << v;
         QhullVertexSet vs= q.firstFacet().vertices();
         os << vs;
         os << "Vertex and vertices w/ FIXUP runId:\n";
         os << v.print();
         os << vs.print("vertices:");
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count("(v"), 10);
         QCOMPARE(s.count(": f"), 2);
+        q.checkAndFreeQhullMemory();
     }
     RboxPoints r10("10 D3");  // Without QhullVertex::facetNeighbors
     {
         Qhull q(r10, "");
         QhullVertex v= q.beginVertex();
         ostringstream os;
         os << "\nTry again with simplicial facets.  No neighboring facets listed for vertices.\n";
         os << "Vertex and vertices:\n";
         os << v;
         q.defineVertexNeighborFacets();
         os << "This time with neighborFacets() defined for all vertices:\n";
         os << v;
         cout << os.str();
         QString s= QString::fromStdString(os.str());
         QCOMPARE(s.count(": f"), 1);
 
         Qhull q2(r10, "v"); // Voronoi diagram
         QhullVertex v2= q2.beginVertex();
         ostringstream os2;
         os2 << "\nTry again with Voronoi diagram of simplicial facets.  Neighboring facets automatically defined for vertices.\n";
         os2 << "Vertex and vertices:\n";
         os2 << v2;
         cout << os2.str();
         QString s2= QString::fromStdString(os2.str());
         QCOMPARE(s2.count(": f"), 1);
+        q.checkAndFreeQhullMemory();
     }
 }//t_io
 
 }//orgQhull
 
 #include "moc/QhullVertex_test.moc"
diff --git a/src/qhulltest/Qhull_test.cpp b/src/qhulltest/Qhull_test.cpp
index e6abc79..8b9d6df 100644
--- a/src/qhulltest/Qhull_test.cpp
+++ b/src/qhulltest/Qhull_test.cpp
@@ -1,375 +1,389 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/Qhull_test.cpp#7 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/Qhull_test.cpp#8 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "Qhull.h"
 #include "QhullError.h"
 #include "RboxPoints.h"
 #include "QhullFacetList.h"
 
 using std::cout;
 using std::endl;
 using std::string;
 
 namespace orgQhull {
 
 //! Test C++ interface to Qhull
 //! See eg/q_test for tests of Qhull commands
 class Qhull_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_construct();
     void t_attribute();
     void t_message();
     void t_getSet();
     void t_getQh();
     void t_getValue();
     void t_foreach();
     void t_modify();
 };//Qhull_test
 
 void
 add_Qhull_test()
 {
     new Qhull_test();
 }
 
 //Executed after each testcase
 void Qhull_test::
 cleanup()
 {
-    UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void Qhull_test::
 t_construct()
 {
     {
         Qhull q;
         QCOMPARE(q.dimension(),0);
         QVERIFY(q.qhullQh()!=0);
         QCOMPARE(QString(q.qhullCommand()),QString(""));
         QCOMPARE(QString(q.rboxCommand()),QString(""));
         try{
             QCOMPARE(q.area(),0.0);
             QFAIL("area() did not fail.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         Qhull q2(q);  // Copy constructor and copy assignment OK if not q.initialized()
         QCOMPARE(q2.dimension(),0);
         q= q2;
         QCOMPARE(q.dimension(),0);
+        q.checkAndFreeQhullMemory();
+        q2.checkAndFreeQhullMemory();
     }
     {
         RboxPoints rbox("10000");
         Qhull q(rbox, "QR0"); // Random points in a randomly rotated cube.
         QCOMPARE(q.dimension(),3);
         QVERIFY(q.volume() < 1.0);
         QVERIFY(q.volume() > 0.99);
         try{
             Qhull q2(q);
             QFAIL("Copy constructor did not fail for initialized Qhull.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         try{
             Qhull q3;
             q3= q;
             QFAIL("Copy assignment did not fail for initialized Qhull source.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         QCOMPARE(q.dimension(),3);
         try{
             Qhull q4;
             q= q4;
             QFAIL("Copy assignment did not fail for initialized Qhull destination.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
         QCOMPARE(q.dimension(),3);
+        q.checkAndFreeQhullMemory();
     }
     {
         double points[] = {
             0, 0,
             1, 0,
             1, 1
         };
         Qhull q("triangle", 2, 3, points, "");
         QCOMPARE(q.dimension(),2);
         QCOMPARE(q.facetCount(),3);
         QCOMPARE(q.vertexCount(),3);
         QCOMPARE(q.dimension(),2);
         QCOMPARE(q.area(), 2.0+sqrt(2.0)); // length of boundary
         QCOMPARE(q.volume(), 0.5);        // the 2-d area
+        q.checkAndFreeQhullMemory();
     }
 }//t_construct
 
 void Qhull_test::
 t_attribute()
 {
     RboxPoints rcube("c");
     {
         double normals[] = {
             0,  -1, -0.5,
            -1,   0, -0.5,
             1,   0, -0.5,
             0,   1, -0.5
         };
         Qhull q;
         q.feasiblePoint << 0.0 << 0.0;
         Coordinates c(std::vector(2, 0.0));
         QVERIFY(q.feasiblePoint==c);
         q.setOutputStream(&cout);
         q.runQhull("normals of square", 3, 4, normals, "H"); // halfspace intersect
         QCOMPARE(q.facetList().count(), 4); // Vertices of square
         cout << "Expecting summary of halfspace intersect\n";
         q.outputQhull();
         q.useOutputStream= false;
         cout << "Expecting no output from qh_fprintf() in Qhull.cpp\n";
         q.outputQhull();
+        q.checkAndFreeQhullMemory();
     }
 }//t_attribute
 
 //! No QhullMessage for errors outside of qhull
 void Qhull_test::
 t_message()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         QCOMPARE(q.qhullMessage(), string(""));
         QCOMPARE(q.qhullStatus(), qh_ERRnone);
         QVERIFY(!q.hasQhullMessage());
         try{
             q.runQhull(rcube, "Fd");
             QFAIL("runQhull Fd did not fail.");
         }catch (const std::exception &e) {
             const char *s= e.what();
             cout << "INFO   : Caught " << s;
             QCOMPARE(QString::fromStdString(s).left(6), QString("QH6029"));
             // FIXUP QH11025 -- review decision to clearQhullMessage at QhullError()            // Cleared when copied to QhullError
             QVERIFY(!q.hasQhullMessage());
             // QCOMPARE(q.qhullMessage(), QString::fromStdString(s).remove(0, 7));
             // QCOMPARE(q.qhullStatus(), 6029);
             q.clearQhullMessage();
             QVERIFY(!q.hasQhullMessage());
         }
         q.appendQhullMessage("Append 1");
         QVERIFY(q.hasQhullMessage());
         QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1"));
         q.appendQhullMessage("\nAppend 2\n");
         QCOMPARE(QString::fromStdString(q.qhullMessage()), QString("Append 1\nAppend 2\n"));
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
         QCOMPARE(QString::fromStdString(q.qhullMessage()), QString(""));
+        q.checkAndFreeQhullMemory();
     }
     {
         cout << "INFO   : Error stream without output stream\n";
         Qhull q;
         q.setErrorStream(&cout);
         q.setOutputStream(0);
         try{
             q.runQhull(rcube, "Fd");
             QFAIL("runQhull Fd did not fail.");
         }catch (const QhullError &e) {
             cout << "INFO   : Caught " << e;
             QCOMPARE(e.errorCode(), 6029);
         }
         //FIXUP QH11026 Qhullmessage cleared when QhullError thrown.  Switched to e
         //QVERIFY(q.hasQhullMessage());
         //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(6), QString("QH6029"));
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
+        q.checkAndFreeQhullMemory();
     }
     {
         cout << "INFO   : Error output sent to output stream without error stream\n";
         Qhull q;
         q.setErrorStream(0);
         q.setOutputStream(&cout);
         try{
             q.runQhull(rcube, "Tz H0");
             QFAIL("runQhull TZ did not fail.");
         }catch (const std::exception &e) {
             const char *s= e.what();
             cout << "INFO   : Caught " << s;
             QCOMPARE(QString::fromAscii(s).left(6), QString("QH6023"));
         }
         //FIXUP QH11026 Qhullmessage cleared when QhullError thrown.  Switched to e
         //QVERIFY(q.hasQhullMessage());
         //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(17), QString("qhull: no message"));
         //QCOMPARE(q.qhullStatus(), 6023);
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
+        q.checkAndFreeQhullMemory();
     }
     {
         cout << "INFO   : No error stream or output stream\n";
         Qhull q;
         q.setErrorStream(0);
         q.setOutputStream(0);
         try{
             q.runQhull(rcube, "Fd");
             QFAIL("outputQhull did not fail.");
         }catch (const std::exception &e) {
             const char *s= e.what();
             cout << "INFO   : Caught " << s;
             QCOMPARE(QString::fromAscii(s).left(6), QString("QH6029"));
         }
         //FIXUP QH11026 Qhullmessage cleared when QhullError thrown.  Switched to e
         //QVERIFY(q.hasQhullMessage());
         //QCOMPARE(QString::fromStdString(q.qhullMessage()).left(9), QString("qhull err"));
         //QCOMPARE(q.qhullStatus(), 6029);
         q.clearQhullMessage();
         QVERIFY(!q.hasQhullMessage());
+        q.checkAndFreeQhullMemory();
     }
 }//t_message
 
 void Qhull_test::
 t_getSet()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         QVERIFY(!q.initialized());
         q.runQhull(rcube, "s");
         QVERIFY(q.initialized());
         QCOMPARE(q.dimension(), 3);
         QhullPoint p= q.origin();
         QCOMPARE(p.dimension(), 3);
         QCOMPARE(p[0]+p[1]+p[2], 0.0);
         q.setErrorStream(&cout);
         q.outputQhull();
+        q.checkAndFreeQhullMemory();
     }
     {
         Qhull q;
         q.runQhull(rcube, "");
         q.setOutputStream(&cout);
         q.outputQhull();
+        q.checkAndFreeQhullMemory();
     }
 }//t_getSet
 
 void Qhull_test::
 t_getQh()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         q.runQhull(rcube, "s");
         QCOMPARE(QString(q.qhullCommand()), QString("qhull s"));
         QCOMPARE(QString(q.rboxCommand()), QString("rbox \"c\""));
         QCOMPARE(q.facetCount(), 6);
         QCOMPARE(q.vertexCount(), 8);
         // Sample fields from Qhull's qhT [libqhull.h]
         QCOMPARE(q.qhullQh()->ALLpoints, 0u);
         QCOMPARE(q.qhullQh()->GOODpoint, 0);
         QCOMPARE(q.qhullQh()->IStracing, 0);
         QCOMPARE(q.qhullQh()->MAXcoplanar+1.0, 1.0); // fuzzy compare
         QCOMPARE(q.qhullQh()->MERGING, 1u);
         QCOMPARE(q.qhullQh()->input_dim, 3);
         QCOMPARE(QString(q.qhullQh()->qhull_options).left(8), QString("  run-id"));
         QCOMPARE(q.qhullQh()->num_facets, 6);
         QCOMPARE(q.qhullQh()->hasTriangulation, 0u);
         QCOMPARE(q.qhullQh()->max_outside - q.qhullQh()->min_vertex + 1.0, 1.0); // fuzzy compare
         QCOMPARE(*q.qhullQh()->gm_matrix+1.0, 1.0); // fuzzy compare
+        q.checkAndFreeQhullMemory();
     }
 }//t_getQh
 
 void Qhull_test::
 t_getValue()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         q.runQhull(rcube, "");
         QCOMPARE(q.area(), 6.0);
         QCOMPARE(q.volume(), 1.0);
+        q.checkAndFreeQhullMemory();
     }
 }//t_getValue
 
 void Qhull_test::
 t_foreach()
 {
     RboxPoints rcube("c");
     {
         Qhull q;
         QCOMPARE(q.beginFacet(),q.endFacet());
         QCOMPARE(q.beginVertex(),q.endVertex());
         q.runQhull(rcube, "");
         QCOMPARE(q.facetList().count(), 6);
 
         // defineVertexNeighborFacets() tested in QhullVertex_test::t_io()
 
         QhullFacetList facets(q.beginFacet(), q.endFacet());
         QCOMPARE(facets.count(), 6);
         QCOMPARE(q.firstFacet(), q.beginFacet());
         QhullVertexList vertices(q.beginVertex(), q.endVertex());
         QCOMPARE(vertices.count(), 8);
         QCOMPARE(q.firstVertex(), q.beginVertex());
         QhullPoints ps= q.points();
         QCOMPARE(ps.count(), 8);
         QhullPointSet ps2= q.otherPoints();
         QCOMPARE(ps2.count(), 0);
         // ps2= q.otherPoints(); //disabled, would not copy the points
         QCOMPARE(q.facetCount(), 6);
         QCOMPARE(q.vertexCount(), 8);
         coordT *c= q.pointCoordinateBegin(); // of q.points()
         QVERIFY(*c==0.5 || *c==-0.5);
         coordT *c3= q.pointCoordinateEnd();
         QVERIFY(c3[-1]==0.5 || c3[-1]==-0.5);
         QCOMPARE(c3-c, 8*3);
         QCOMPARE(q.vertexList().count(), 8);
+        q.checkAndFreeQhullMemory();
     }
 }//t_foreach
 
 void Qhull_test::
 t_modify()
 {
     //addPoint() tested in t_foreach
     RboxPoints diamond("d");
     Qhull q(diamond, "o");
     q.setOutputStream(&cout);
     cout << "Expecting vertexList and facetList of a 3-d diamond.\n";
     q.outputQhull();
     cout << "Expecting normals of a 3-d diamond.\n";
     q.outputQhull("n");
     // runQhull tested in t_attribute(), t_message(), etc.
+    q.checkAndFreeQhullMemory();
 }//t_modify
 
 }//orgQhull
 
 // Redefine Qhull's usermem.c
 void qh_exit(int exitcode) {
     cout << "FAIL!  : Qhull called qh_exit().  Qhull's error handling not available.\n.. See the corresponding Qhull:qhull_message or setErrorStream().\n";
     exit(exitcode);
 }
 void qh_free(void *mem) {
     free(mem);
 }
 void *qh_malloc(size_t size) {
     return malloc(size);
 }
 
 #if 0
 template<> char * QTest::
 toString(const std::string &s)
 {
     QByteArray ba = s.c_str();
     return qstrdup(ba.data());
 }
 #endif
 
 #include "moc/Qhull_test.moc"
diff --git a/src/qhulltest/RboxPoints_test.cpp b/src/qhulltest/RboxPoints_test.cpp
index ba5525b..4822da3 100644
--- a/src/qhulltest/RboxPoints_test.cpp
+++ b/src/qhulltest/RboxPoints_test.cpp
@@ -1,216 +1,216 @@
 /****************************************************************************
 **
-** Copyright (c) 2006-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/RboxPoints_test.cpp#4 $$Change: 1490 $
-** $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $
+** Copyright (c) 2006-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/RboxPoints_test.cpp#6 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "RboxPoints.h"
 #include "QhullError.h"
 
 using std::cout;
 using std::endl;
 using std::ostringstream;
 using std::string;
 using std::stringstream;
 
 namespace orgQhull {
 
 //! Test C++ interface to Rbox
 //! See eg/q_test for tests of rbox commands
 class RboxPoints_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void t_construct();
     void t_error();
     void t_test();
     void t_getSet();
     void t_foreach();
     void t_change();
     void t_ostream();
 };
 
 void
 add_RboxPoints_test()
 {
     new RboxPoints_test();
 }
 
 void RboxPoints_test::
 t_construct()
 {
     RboxPoints rp;
     QCOMPARE(rp.dimension(), 0);
     QCOMPARE(rp.count(), 0);
     QVERIFY(QString::fromStdString(rp.comment()) != QString(""));
     QVERIFY(rp.isEmpty());
     QVERIFY(!rp.hasRboxMessage());
     QCOMPARE(rp.rboxStatus(), qh_ERRnone);
     QCOMPARE(QString::fromStdString(rp.rboxMessage()), QString("rbox warning: no points generated\n"));
 
     RboxPoints rp2("c"); // 3-d cube
     QCOMPARE(rp2.dimension(), 3);
     QCOMPARE(rp2.count(), 8);
     QCOMPARE(QString::fromStdString(rp2.comment()), QString("rbox \"c\""));
     QVERIFY(!rp2.isEmpty());
     QVERIFY(!rp2.hasRboxMessage());
     QCOMPARE(rp2.rboxStatus(), qh_ERRnone);
     QCOMPARE(QString::fromStdString(rp2.rboxMessage()), QString("rbox: OK\n"));
 }//t_construct
 
 void RboxPoints_test::
 t_error()
 {
     RboxPoints rp;
     try{
         rp.appendPoints("D0 c");
         QFAIL("'D0 c' did not fail.");
     }catch (const std::exception &e) {
         const char *s= e.what();
         cout << "INFO   : Caught " << s;
         QCOMPARE(QString(s).left(6), QString("QH6189"));
         QVERIFY(rp.hasRboxMessage());
         QCOMPARE(QString::fromStdString(rp.rboxMessage()).left(8), QString("rbox err"));
         QCOMPARE(rp.rboxStatus(), 6189);
         rp.clearRboxMessage();
         QVERIFY(!rp.hasRboxMessage());
     }
     try{
         RboxPoints rp2;
         rp2.setDimension(-1);
         QFAIL("setDimension(-1) did not fail.");
     }catch (const RoadError &e) {
         const char *s= e.what();
         cout << "INFO   : Caught " << s;
         QCOMPARE(QString(s).left(7), QString("QH10062"));
         QCOMPARE(e.errorCode(), 10062);
         QCOMPARE(QString::fromStdString(e.what()), QString(s));
         RoadLogEvent logEvent= e.roadLogEvent();
         QCOMPARE(logEvent.int1(), -1);
     }
 }//t_error
 
 void RboxPoints_test::
 t_test()
 {
     // isEmpty -- t_construct
 }//t_test
 
 void RboxPoints_test::
 t_getSet()
 {
     // comment -- t_construct
     // count -- t_construct
     // dimension -- t_construct
 
     RboxPoints rp;
     QCOMPARE(rp.dimension(), 0);
     rp.setDimension(2);
     QCOMPARE(rp.dimension(), 2);
     rp.setDimension(2);
     QCOMPARE(rp.dimension(), 2);
     try{
         rp.setDimension(102);
         QFAIL("setDimension(102) did not fail.");
     }catch (const std::exception &e) {
         cout << "INFO   : Caught " << e.what();
     }
     QCOMPARE(rp.newCount(), 0);
     rp.appendPoints("D2 P1 P2");
     QCOMPARE(rp.count(), 2);
     QCOMPARE(rp.newCount(), 2); // From previous appendPoints();
     PointCoordinates pc(2);
     pc << 1.0 << 0.0 << 2.0 << 0.0;
     QCOMPARE(pc.dimension(), 2);
     QCOMPARE(pc.count(), 2);
     QVERIFY(rp==pc);
     rp.setNewCount(10);  // Normally only used by appendPoints for rbox processing
     QCOMPARE(rp.newCount(), 10);
     rp.reservePoints();
     QVERIFY(rp==pc);
 }//t_getSet
 
 void RboxPoints_test::
 t_foreach()
 {
     RboxPoints rp("c");
     Coordinates::ConstIterator cci= rp.beginCoordinates();
     orgQhull::Coordinates::Iterator ci= rp.beginCoordinates();
     QCOMPARE(*cci, -0.5);
     QCOMPARE(*ci, *cci);
     int i=1;
     while(++cci
 #include 
 #include "RoadTest.h"
 
 using std::cout;
 using std::endl;
 
 namespace orgQhull {
 
 #//class variable
 
 QList RoadTest::
 s_testcases;
 
 int RoadTest::
 s_test_count= 0;
 
 int RoadTest::
 s_test_fail= 0;
 
 QStringList RoadTest::
 s_failed_tests;
 
 #//Slot
 
 //! Executed after each test
 void RoadTest::
 cleanup()
 {
     s_test_count++;
     if(QTest::currentTestFailed()){
         recordFailedTest();
     }
 }//cleanup
 
 #//Helper
 
 void RoadTest::
 recordFailedTest()
 {
     s_test_fail++;
     QString className= metaObject()->className();
     s_failed_tests << className + "::" + QTest::currentTestFunction();
 }
 
 #//class function
 
 int RoadTest::
 runTests(QStringList arguments)
 {
     int result= 0; // assume success
 
     foreach(RoadTest *testcase, s_testcases){
         try{
             result += QTest::qExec(testcase, arguments);
         }catch(const std::exception &e){
             cout << "FAIL!  : Threw error ";
             cout << e.what() << endl;
     s_test_count++;
             testcase->recordFailedTest();
             // Qt 4.5.2 OK.  In Qt 4.3.3, qtestcase did not clear currentTestObject
         }
     }
     if(s_test_fail){
         cout << "Failed " << s_test_fail << " of " << s_test_count << " tests.\n";
         cout << s_failed_tests.join("\n").toLocal8Bit().constData() << std::endl;
     }else{
         cout << "Passed " << s_test_count << " tests.\n";
     }
     return result;
 }//runTests
 
 }//orgQhull
 
 #include "moc/moc_RoadTest.cpp"
diff --git a/src/qhulltest/RoadTest.h b/src/qhulltest/RoadTest.h
index f36f963..df3bdf3 100644
--- a/src/qhulltest/RoadTest.h
+++ b/src/qhulltest/RoadTest.h
@@ -1,101 +1,101 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/RoadTest.h#1 $$Change: 1490 $
-** $Date: 2012/02/19 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/RoadTest.h#3 $$Change: 1810 $
+** $Date: 2015/01/17 $$Author: bbarber $
 **
 ****************************************************************************/
 
 #ifndef ROADTEST_H
 #define ROADTEST_H
 
 //pre-compiled with RoadTest.h
 #include     // Qt C++ Framework
 #include 
 
 #define QHULL_USES_QT 1
 
 namespace orgQhull {
 
 #//!\name Defined here
 
     //! RoadTest -- Generic test for Qt's QTest
     class RoadTest;
     //! TESTadd_(t) -- Add a RoadTest
 
 /** Test Name objects using Qt's QTestLib
 
 Template:
 
 class Name_test : public RoadTest
 {
     Q_OBJECT
 #//Test slot
 private slots:
     void t_name();
     //Executed before any test
     void initTestCase();
     void init();          // Each test
     //Executed after each test
     void cleanup(); //RoadTest::cleanup();
     // Executed after last test
     void cleanupTestCase();
 };
 
 void
 add_Name_test()
 {
     new Name_test();
 }
 
 Send additional output to cout
 */
 
 class RoadTest : public QObject
 {
     Q_OBJECT
 
 #//!\name Class globals
 protected:
     static QList
                         s_testcases; ///! List of testcases to execute.  Initialized via add_...()
     static int          s_test_count; ///! Total number of tests executed
     static int          s_test_fail; ///! Number of failed tests
     static QStringList  s_failed_tests; ///! List of failed tests
 
 #//!\name Test slots
 public slots:
     void cleanup();
 
 public:
 #//!\name Constructors, etc.
     RoadTest()  { s_testcases.append(this); }
     ~RoadTest() { s_testcases.removeAll(this); }
 
 #//Helper
     void                recordFailedTest();
 
 
 #//!\name Class functions
     static int          runTests(QStringList arguments);
 
 };//RoadTest
 
 #define TESTadd_(t) extern void t(); t();
 
 
 }//orgQhull
 
 namespace QTest{
 
 template<>
 inline char *
 toString(const std::string &s)
 {
     return qstrdup(s.c_str());
 }
 
 }//namespace QTest
 
 #endif //ROADTEST_H
 
diff --git a/src/qhulltest/UsingLibQhull_test.cpp b/src/qhulltest/UsingLibQhull_test.cpp
index 56aa27a..a4e49ed 100644
--- a/src/qhulltest/UsingLibQhull_test.cpp
+++ b/src/qhulltest/UsingLibQhull_test.cpp
@@ -1,208 +1,208 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/UsingLibQhull_test.cpp#6 $$Change: 1709 $
-** $DateTime: 2014/03/26 22:27:14 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/UsingLibQhull_test.cpp#7 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include "RoadTest.h" // QT_VERSION
 
 #include "UsingLibQhull.h"
 #include "QhullError.h"
 #include "Qhull.h"
 
 using std::cout;
 using std::endl;
 using std::string;
 
 namespace orgQhull {
 
 //! Test C++ interface to Qhull
 //! See eg/q_test for tests of Qhull commands
 class UsingLibQhull_test : public RoadTest
 {
     Q_OBJECT
 
 #//Test slots
 private slots:
     void cleanup();
     void t_classMembers();
     void t_globalPoints();
     void t_UsingLibQhull();
     void t_methods();
     void t_cleanuptestcase();
 };//UsingLibQhull_test
 
 void
 add_UsingLibQhull_test()
 {
     new UsingLibQhull_test();
 }
 
 //Executed after each testcase
 void UsingLibQhull_test::
 cleanup()
 {
     UsingLibQhull::checkQhullMemoryEmpty();
     RoadTest::cleanup();
 }
 
 void UsingLibQhull_test::
 t_classMembers()
 {
     {
         //checkQhullMemoryEmpty tested by cleanup()
         QCOMPARE(UsingLibQhull::globalMachineEpsilon()+1.0, 1.0);
         RboxPoints r10("10");
         Qhull q(r10,"v");  // voronoi diagram of 10 points
         UsingLibQhull::unsetGlobalAngleEpsilon();
         UsingLibQhull::unsetGlobalDistanceEpsilon();
         cout << "MachineEpsilon " << UsingLibQhull::globalMachineEpsilon()
             << " angleEpsilon " << UsingLibQhull::globalAngleEpsilon()
             << " distanceEpsilon " << UsingLibQhull::globalDistanceEpsilon()
             << endl;
         QCOMPARE(UsingLibQhull::currentAngleEpsilon()+1.0, 1.0);
         QVERIFY(UsingLibQhull::currentAngleEpsilon() > UsingLibQhull::globalMachineEpsilon());
         QCOMPARE(UsingLibQhull::currentDistanceEpsilon()+1.0, 1.0);
         QVERIFY(UsingLibQhull::currentDistanceEpsilon() >= UsingLibQhull::currentAngleEpsilon());
         QCOMPARE(UsingLibQhull::globalAngleEpsilon()+1.0, UsingLibQhull::currentAngleEpsilon()+1.0);
         QCOMPARE(UsingLibQhull::currentVertexDimension(), q.dimension());
         QCOMPARE(UsingLibQhull::globalDistanceEpsilon()+1.0, UsingLibQhull::currentDistanceEpsilon()+1.0);
         UsingLibQhull::setGlobalAngleEpsilon(1.0);
         UsingLibQhull::setGlobalDistanceEpsilon(1.0);
         cout << " Global angleEpsilon " << UsingLibQhull::globalAngleEpsilon()
             << " distanceEpsilon " << UsingLibQhull::globalDistanceEpsilon()
             << endl;
         QCOMPARE(UsingLibQhull::globalAngleEpsilon(), UsingLibQhull::globalDistanceEpsilon());
         QVERIFY(UsingLibQhull::currentAngleEpsilon() != UsingLibQhull::globalAngleEpsilon());
         UsingLibQhull::setGlobalVertexDimension(3);
         QCOMPARE(UsingLibQhull::globalVertexDimension(), UsingLibQhull::currentVertexDimension());
         UsingLibQhull::setGlobalVertexDimension(2);
         QCOMPARE(UsingLibQhull::globalVertexDimension(), 2);
         QCOMPARE(UsingLibQhull::currentVertexDimension(), q.dimension());
         QVERIFY(UsingLibQhull::currentDistanceEpsilon() != UsingLibQhull::globalDistanceEpsilon());
         UsingLibQhull::unsetGlobalAngleEpsilon();
         UsingLibQhull::unsetGlobalVertexDimension();
         UsingLibQhull::unsetGlobalDistanceEpsilon();
         QCOMPARE(UsingLibQhull::currentAngleEpsilon()+1.0, UsingLibQhull::globalAngleEpsilon()+1.0);
         QCOMPARE(UsingLibQhull::globalVertexDimension(), UsingLibQhull::currentVertexDimension());
         QCOMPARE(UsingLibQhull::currentDistanceEpsilon()+1.0, UsingLibQhull::globalDistanceEpsilon()+1.0);
         UsingLibQhull::setGlobals();
     }
     QCOMPARE(UsingLibQhull::globalAngleEpsilon()+1.0, 1.0);
     QCOMPARE(UsingLibQhull::globalVertexDimension(), 4); // 'v'.  VertexDimension is only used for QhullVertex where dim>15
     QCOMPARE(UsingLibQhull::globalDistanceEpsilon()+1.0, 1.0);
     UsingLibQhull::unsetGlobals();
     try{
         cout << UsingLibQhull::globalVertexDimension();
         QFAIL("Did not throw error for undefined dimension.");
     }catch(const std::exception &e){
         cout << "INFO     Caught error -- " << e.what() << endl;
     }
 }//t_classMembers
 
 void UsingLibQhull_test::
 t_globalPoints()
 {
     const coordT *r10PointsBegin;
     {
         RboxPoints r10("10");
         Qhull q(r10,"v");  // voronoi diagram of 10 points
         UsingLibQhull::unsetGlobalPoints();
         int dimension;
         const coordT *pointsEnd;
         const coordT *pointsBegin= UsingLibQhull::globalPoints(&dimension, &pointsEnd);
         cout << "pointsBegin " << pointsBegin
             << " pointsEnd " << pointsEnd
             << " dimension " << dimension
             << endl;
         int dimension2;
         const coordT *pointsEnd2;
         const coordT *pointsBegin2= UsingLibQhull::currentPoints(&dimension2, &pointsEnd2);
         QCOMPARE(pointsBegin2, pointsBegin);
         QCOMPARE(pointsEnd2, pointsEnd);
         QCOMPARE(dimension2, dimension);
         coordT c[]= { 1.0,2.0, 3.0,4.0, 5.0,6.0 };
         UsingLibQhull::setGlobalPoints(2, c, c+3*2);
         pointsBegin= UsingLibQhull::globalPoints(&dimension, &pointsEnd);
         QCOMPARE(pointsBegin, c);
         QCOMPARE(pointsEnd[-1], 6.0);
         QCOMPARE(dimension, 2);
         UsingLibQhull::unsetGlobalPoints();
         pointsBegin= UsingLibQhull::globalPoints(&dimension, &pointsEnd);
         QCOMPARE(pointsBegin, pointsBegin2);
         QCOMPARE(pointsEnd, pointsEnd2);
         QCOMPARE(dimension, dimension2);
         UsingLibQhull::setGlobals();
         r10PointsBegin= pointsBegin;
     }
     int dimension3;
     const coordT *pointsEnd3;
     const coordT *pointsBegin3= UsingLibQhull::currentPoints(&dimension3, &pointsEnd3);
     QCOMPARE(pointsBegin3, r10PointsBegin); // Memory was freed
     QCOMPARE(pointsEnd3, r10PointsBegin+10*4);
     QCOMPARE(dimension3, 4);
     UsingLibQhull::unsetGlobals();
     try{
         pointsBegin3= UsingLibQhull::globalPoints(&dimension3, &pointsEnd3);
         QFAIL("Did not throw error for undefined global points.");
     }catch(const std::exception &e){
         cout << "INFO     Caught error -- " << e.what() << endl;
     }
 }//t_globalPoints
 
 void UsingLibQhull_test::
 t_UsingLibQhull()
 {
     {
         Qhull q;
         UsingLibQhull uq(&q); // Normally created in a method using 'this'
 
         try{
             Qhull q2; // If qh_QHpointer, QhullQh() calls usinlibqhull()
             UsingLibQhull uq2(&q2);
             QFAIL("UsingLibQhull did not fail.");
         }catch (const std::exception &e) {
             cout << "INFO   : Caught " << e.what();
         }
     }
     Qhull q3;
     UsingLibQhull uq3(&q3);
     // UsingLibQhull uq4; // Default constructors disabled.
 }//t_UsingLibQhull
 
 void UsingLibQhull_test::
 t_methods()
 {
     Qhull q;
     UsingLibQhull u(&q); // Normally created in a method using 'this'
     QVERIFY(u.defined());
     u.maybeThrowQhullMessage(0);  // Nothing thrown
     try{
         u.maybeThrowQhullMessage(1);
         QFAIL("maybeThrowQhullMessage(1) did not fail.");
     }catch (const std::exception &e) {
         cout << "INFO   : Caught " << e.what();
     }
     u.maybeThrowQhullMessage(2, UsingLibQhull::NOthrow);
     try{
         throw QhullError(10054, "Report previous NOthrow error");
     }catch (const std::exception &e) {
         cout << "INFO   : " << e.what();
     }
 }//t_methods
 
 // Executed after last test
 void UsingLibQhull_test::
 t_cleanuptestcase()
 {
     UsingLibQhull::unsetGlobals();
 }//t_cleanuptestcase
 
 }//orgQhull
 
 #include "moc/UsingLibQhull_test.moc"
 
diff --git a/src/qhulltest/qhulltest.cpp b/src/qhulltest/qhulltest.cpp
index 9221f63..80e8221 100644
--- a/src/qhulltest/qhulltest.cpp
+++ b/src/qhulltest/qhulltest.cpp
@@ -1,87 +1,87 @@
 /****************************************************************************
 **
-** Copyright (c) 2008-2014 C.B. Barber. All rights reserved.
-** $Id: //main/2011/qhull/src/qhulltest/qhulltest.cpp#10 $$Change: 1799 $
-** $DateTime: 2014/12/17 16:17:40 $$Author: bbarber $
+** Copyright (c) 2008-2015 C.B. Barber. All rights reserved.
+** $Id: //main/2011/qhull/src/qhulltest/qhulltest.cpp#11 $$Change: 1810 $
+** $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 **
 ****************************************************************************/
 
 //pre-compiled headers
 #include 
 #include 
 #include 
 #include 
 #include "RoadTest.h"
 
 #include "../libqhullcpp/RoadError.h"
 
 using std::cout;
 using std::endl;
 
 namespace orgQhull {
 
 void addQhullTests(QStringList &args)
 {
     TESTadd_(add_QhullPointSet_test); //copy
     TESTadd_(add_QhullPoint_test); //copy
 
     if(args.contains("--all")){
         args.removeAll("--all");
         // up-to-date
     /**FIXUP
         TESTadd_(add_Coordinates_test);
         TESTadd_(add_PointCoordinates_test);
         TESTadd_(add_QhullFacet_test);
         TESTadd_(add_QhullFacetList_test);
         TESTadd_(add_QhullFacetSet_test);
         TESTadd_(add_QhullHyperplane_test);
         TESTadd_(add_QhullLinkedList_test);
         TESTadd_(add_QhullPoint_test);
         TESTadd_(add_QhullPoints_test);
         TESTadd_(add_QhullPointSet_test);
         TESTadd_(add_QhullRidge_test);
         TESTadd_(add_QhullSet_test);
         TESTadd_(add_QhullVertex_test);
         TESTadd_(add_RboxPoints_test);
         // qhullStat
         TESTadd_(add_Qhull_test);
     */
     }//--all
 }//addQhullTests
 
 int main(int argc, char *argv[])
 {
     QCoreApplication app(argc, argv);
     QStringList args= app.arguments();
     bool isAll= args.contains("--all");
     addQhullTests(args);
     int status=1010;
     try{
         status= RoadTest::runTests(args);
     }catch(const std::exception &e){
         cout << "FAIL!  : runTests() did not catch error\n";
         cout << e.what() << endl;
         if(!RoadError::emptyGlobalLog()){
             cout << RoadError::stringGlobalLog() << endl;
             RoadError::clearGlobalLog();
         }
     }
     if(!RoadError::emptyGlobalLog()){
         cout << RoadError::stringGlobalLog() << endl;
         RoadError::clearGlobalLog();
     }
     if(isAll){
         cout << "Finished test of libqhullcpp.  Test libqhull with eg/q_test" << endl;
     }else{
         cout << "Finished test of one class.  Test all classes with 'qhulltest --all'" << endl;
     }
     return status;
 }
 
 }//orgQhull
 
 int main(int argc, char *argv[])
 {
     return orgQhull::main(argc, argv); // Needs RoadTest:: for TESTadd_() linkage
 }
 
diff --git a/src/qvoronoi/qvoronoi.c b/src/qvoronoi/qvoronoi.c
index b5fdf68..09447b4 100644
--- a/src/qvoronoi/qvoronoi.c
+++ b/src/qvoronoi/qvoronoi.c
@@ -1,313 +1,313 @@
 /*
  ---------------------------------
 
    qvoronoi.c
      compute Voronoi diagrams and furthest-point Voronoi
      diagrams using qhull
 
    see unix.c for full interface
 
-   Copyright (c) 1993-2014, The Geometry Center
+   Copyright (c) 1993-2015, The Geometry Center
 */
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include "libqhull.h"
 #include "mem.h"
 #include "qset.h"
 
 #if __MWERKS__ && __POWERPC__
 #include 
 #include 
 #include 
 #include 
 
 #elif __cplusplus
 extern "C" {
   int isatty(int);
 }
 
 #elif _MSC_VER
 #include 
 #define isatty _isatty
 int _isatty(int);
 
 #else
 int isatty(int);  /* returns 1 if stdin is a tty
                    if "Undefined symbol" this can be deleted along with call in main() */
 #endif
 
 /*---------------------------------
 
   qh_prompt
     long prompt for qhull
 
   notes:
     restricted version of libqhull.c
 
   see:
     concise prompt below
 */
 
 /* duplicated in qvoron_f.htm and qvoronoi.htm
    QJ and Qt are deprecated, but allowed for backwards compatibility
 */
 char hidden_options[]=" d n m v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V Fa FA FC Fp FS Ft FV Pv Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
 
 char qh_prompta[]= "\n\
 qvoronoi- compute the Voronoi diagram\n\
     http://www.qhull.org  %s\n\
 \n\
 input (stdin):\n\
     first lines: dimension and number of points (or vice-versa).\n\
     other lines: point coordinates, best if one point per line\n\
     comments:    start with a non-numeric character\n\
 \n\
 options:\n\
     Qu   - compute furthest-site Voronoi diagram\n\
 \n\
 Qhull control options:\n\
     Qz   - add point-at-infinity to Voronoi diagram\n\
 %s%s%s%s";  /* split up qh_prompt for Visual C++ */
 char qh_promptb[]= "\
     Qs   - search all points for the initial simplex\n\
     QGn  - Voronoi vertices if visible from point n, -n if not\n\
     QVn  - Voronoi vertices for input point n, -n if not\n\
 \n\
 ";
 char qh_promptc[]= "\
 Trace options:\n\
     T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
     Tc   - check frequently during execution\n\
     Ts   - statistics\n\
     Tv   - verify result: structure, convexity, and in-circle test\n\
     Tz   - send all output to stdout\n\
     TFn  - report summary when n or more facets created\n\
     TI file - input data from file, no spaces or single quotes\n\
     TO file - output results to file, may be enclosed in single quotes\n\
     TPn  - turn on tracing when point n added to hull\n\
      TMn - turn on tracing at merge n\n\
      TWn - trace merge facets when width > n\n\
     TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
      TCn - stop qhull after building cone for point n (see TVn)\n\
 \n\
 Precision options:\n\
     Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
      An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
            C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
     Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
     Wn   - min facet width for non-coincident point (before roundoff)\n\
 \n\
 Output formats (may be combined; if none, produces a summary to stdout):\n\
     s    - summary to stderr\n\
     p    - Voronoi vertices\n\
     o    - OFF format (dim, Voronoi vertices, and Voronoi regions)\n\
     i    - Delaunay regions (use 'Pp' to avoid warning)\n\
     f    - facet dump\n\
 \n\
 ";
 char qh_promptd[]= "\
 More formats:\n\
     Fc   - count plus coincident points (by Voronoi vertex)\n\
     Fd   - use cdd format for input (homogeneous with offset first)\n\
     FD   - use cdd format for output (offset first)\n\
     FF   - facet dump without ridges\n\
     Fi   - separating hyperplanes for bounded Voronoi regions\n\
     FI   - ID for each Voronoi vertex\n\
     Fm   - merge count for each Voronoi vertex (511 max)\n\
     Fn   - count plus neighboring Voronoi vertices for each Voronoi vertex\n\
     FN   - count and Voronoi vertices for each Voronoi region\n\
     Fo   - separating hyperplanes for unbounded Voronoi regions\n\
     FO   - options and precision constants\n\
     FP   - nearest point and distance for each coincident point\n\
     FQ   - command used for qvoronoi\n\
     Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
                     for output: #Voronoi regions, #Voronoi vertices,\n\
                                 #coincident points, #non-simplicial regions\n\
                     #real (2), max outer plane and min vertex\n\
     Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
     Fx   - extreme points of Delaunay triangulation (on convex hull)\n\
 \n\
 ";
 char qh_prompte[]= "\
 Geomview options (2-d only)\n\
     Ga   - all points as dots\n\
      Gp  -  coplanar points and vertices as radii\n\
      Gv  -  vertices as spheres\n\
     Gi   - inner planes only\n\
      Gn  -  no planes\n\
      Go  -  outer planes only\n\
     Gc   - centrums\n\
     Gh   - hyperplane intersections\n\
     Gr   - ridges\n\
     GDn  - drop dimension n in 3-d and 4-d output\n\
 \n\
 Print options:\n\
     PAn  - keep n largest Voronoi vertices by 'area'\n\
     Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
     PDk:n - drop facet if normal[k] >= n\n\
     Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')\n\
     PFn  - keep Voronoi vertices whose 'area' is at least n\n\
     PG   - print neighbors of good Voronoi vertices\n\
     PMn  - keep n Voronoi vertices with most merges\n\
     Po   - force output.  If error, output neighborhood of facet\n\
     Pp   - do not report precision problems\n\
 \n\
     .    - list of all options\n\
     -    - one line descriptions of all options\n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt2
     synopsis for qhull
 */
 char qh_prompt2[]= "\n\
 qvoronoi- compute the Voronoi diagram.  Qhull %s\n\
     input (stdin): dimension, number of points, point coordinates\n\
     comments start with a non-numeric character\n\
 \n\
 options (qvoronoi.htm):\n\
     Qu   - compute furthest-site Voronoi diagram\n\
     Tv   - verify result: structure, convexity, and in-circle test\n\
     .    - concise list of all options\n\
     -    - one-line description of all options\n\
 \n\
 output options (subset):\n\
     s    - summary of results (default)\n\
     p    - Voronoi vertices\n\
     o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)\n\
     FN   - count and Voronoi vertices for each Voronoi region\n\
     Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
     Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded\n\
     G    - Geomview output (2-d only)\n\
     QVn  - Voronoi vertices for input point n, -n if not\n\
     TO file- output results to file, may be enclosed in single quotes\n\
 \n\
 examples:\n\
 rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi\n\
 rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv\n\
 rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo\n\
 rbox c G1 d D2 | qvoronoi s p       rbox c P0 D2 | qvoronoi s Fv QV0\n\
 \n\
 ";
 /* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
 
 /*---------------------------------
 
   qh_prompt3
     concise prompt for qhull
 */
 char qh_prompt3[]= "\n\
 Qhull %s.\n\
 Except for 'F.' and 'PG', upper-case options take an argument.\n\
 \n\
  OFF_format     p_vertices     i_delaunay     summary        facet_dump\n\
 \n\
  Fcoincident    Fd_cdd_in      FD_cdd_out     FF-dump-xridge Fi_bounded\n\
  Fxtremes       Fmerges        Fneighbors     FNeigh_region  FOptions\n\
  Fo_unbounded   FPoint_near    FQvoronoi      Fsummary       Fvoronoi\n\
  FIDs\n\
 \n\
  Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
  Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
 \n\
  PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
  PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
 \n\
  QG_vertex_good Qsearch_1st    Qupper_voronoi QV_point_good  Qzinfinite\n\
  T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
  TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
  TWide_trace    TVertex_stop   TCone_stop\n\
 \n\
  Angle_max      Centrum_size   Random_dist    Wide_outside\n\
 ";
 
 /*---------------------------------
 
   main( argc, argv )
     processes the command line, calls qhull() to do the work, and exits
 
   design:
     initializes data structures
     reads points
     finishes initialization
     computes convex hull and other structures
     checks the result
     writes the output
     frees memory
 */
 int main(int argc, char *argv[]) {
   int curlong, totlong; /* used !qh_NOmem */
   int exitcode, numpoints, dim;
   coordT *points;
   boolT ismalloc;
 
 #if __MWERKS__ && __POWERPC__
   char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
   SIOUXSettings.showstatusline= false;
   SIOUXSettings.tabspaces= 1;
   SIOUXSettings.rows= 40;
   if (setvbuf(stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
   || setvbuf(stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
   || (stdout != stderr && setvbuf(stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
     fprintf(stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
   argc= ccommand(&argv);
 #endif
 
   if ((argc == 1) && isatty( 0 /*stdin*/)) {
     fprintf(stdout, qh_prompt2, qh_version);
     exit(qh_ERRnone);
   }
   if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompta, qh_version,
                 qh_promptb, qh_promptc, qh_promptd, qh_prompte);
     exit(qh_ERRnone);
   }
   if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
     fprintf(stdout, qh_prompt3, qh_version);
     exit(qh_ERRnone);
   }
   qh_init_A(stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
   exitcode= setjmp(qh errexit); /* simple statement for CRAY J916 */
   if (!exitcode) {
     qh_option("voronoi  _bbound-last  _coplanar-keep", NULL, NULL);
     qh DELAUNAY= True;     /* 'v'   */
     qh VORONOI= True;
     qh SCALElast= True;    /* 'Qbb' */
     qh_checkflags(qh qhull_command, hidden_options);
     qh_initflags(qh qhull_command);
     points= qh_readpoints(&numpoints, &dim, &ismalloc);
     if (dim >= 5) {
       qh_option("_merge-exact", NULL, NULL);
       qh MERGEexact= True; /* 'Qx' always */
     }
     qh_init_B(points, numpoints, dim, ismalloc);
     qh_qhull();
     qh_check_output();
     qh_produce_output();
     if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
       qh_check_points();
     exitcode= qh_ERRnone;
   }
   qh NOerrexit= True;  /* no more setjmp */
 #ifdef qh_NOmem
   qh_freeqhull( True);
 #else
   qh_freeqhull( False);
   qh_memfreeshort(&curlong, &totlong);
   if (curlong || totlong)
     fprintf(stderr, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n",
        totlong, curlong);
 #endif
   return exitcode;
 } /* main */
 
diff --git a/src/testqset/testqset.c b/src/testqset/testqset.c
index 263fc40..4f632bd 100644
--- a/src/testqset/testqset.c
+++ b/src/testqset/testqset.c
@@ -1,875 +1,879 @@
 /*
  ---------------------------------
 
    testset.c -- test qset.c and its use of mem.c
 
    The test sets are pointers to int.  Normally a set is a pointer to a type (e.g., facetT, ridgeT, etc.).
    For consistency in notation, an "int" is typedef'd to i2T
 
 Functions and macros from qset.h.  Counts occurrences in this test.  Does not correspond to thoroughness.
     qh_setaddsorted -- 4 tests
     qh_setaddnth -- 1 test
     qh_setappend -- 7 tests
     qh_setappend_set -- 1 test
     qh_setappend2ndlast -- 1 test
     qh_setcheck -- lots of tests
     qh_setcompact -- 7 tests
     qh_setcopy -- 3 tests
     qh_setdel -- 1 tests
     qh_setdellast -- 1 tests
     qh_setdelnth -- 2 tests
     qh_setdelnthsorted -- 2 tests
     qh_setdelsorted -- 1 test
     qh_setduplicate -- not testable here
     qh_setequal -- 4 tests
     qh_setequal_except -- 2 tests
     qh_setequal_skip -- 2 tests
     qh_setfree -- 11+ tests
     qh_setfree2 -- not testable here
     qh_setfreelong -- 2 tests
     qh_setin -- 3 tests
     qh_setindex -- 4 tests
     qh_setlarger -- 1 test
     qh_setlast -- 2 tests
     qh_setnew -- 6 tests
     qh_setnew_delnthsorted
     qh_setprint -- tested elsewhere
     qh_setreplace -- 1 test
     qh_setsize -- 9+ tests
     qh_settemp -- 2 tests
     qh_settempfree -- 1 test
     qh_settempfree_all -- 1 test
     qh_settemppop -- 1 test
     qh_settemppush -- 1 test
     qh_settruncate -- 3 tests
     qh_setunique -- 3 tests
     qh_setzero -- 1 test
     FOREACHint_ -- 2 test
     FOREACHint4_
     FOREACHint_i_ -- 1 test
     FOREACHintreverse_
     FOREACHintreverse12_
     FOREACHsetelement_ -- 1 test
     FOREACHsetelement_i_ -- 1 test
     FOREACHsetelementreverse_ -- 1 test
     FOREACHsetelementreverse12_ -- 1 test
     SETelem_ -- 3 tests
     SETelemaddr_ -- 2 tests
     SETelemt_ -- not tested (generic)
     SETempty_ -- 1 test
     SETfirst_ -- 4 tests
     SETfirstt_ -- 2 tests
     SETindex_ -- 2 tests
     SETref_ -- 2 tests
     SETreturnsize_ -- 2 tests
     SETsecond_ -- 1 test
     SETsecondt_ -- 2 tests
     SETtruncate_ -- 2 tests
+
+    Copyright (c) 2012-2015 C.B. Barber. All rights reserved.
+    $Id: //main/2011/qhull/src/testqset/testqset.c#5 $$Change: 1810 $
+    $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include 
 #include 
 #include 
 #include 
 
 #include "qset.h"
 #include "mem.h"
 
 typedef int i2T;
 #define MAXerrorCount 100 /* quit after n errors */
 
 #define FOREACHint_( ints ) FOREACHsetelement_( i2T, ints, i2)
 #define FOREACHint4_( ints ) FOREACHsetelement_( i2T, ints, i4)
 #define FOREACHint_i_( ints ) FOREACHsetelement_i_( i2T, ints, i2)
 #define FOREACHintreverse_( ints ) FOREACHsetelementreverse_( i2T, ints, i2)
 #define FOREACHintreverse12_( ints ) FOREACHsetelementreverse12_( i2T, ints, i2)
 
 enum {
     MAXint= 0x7fffffff,
 };
 
 char prompt[]= "testqset N [M] [T5] -- Test qset.c and mem.c\n\
   Test qsets of 0..N integers with a check every M iterations (default ~log10)\n\
   Additional checking and logging if M is 1\n\
   T5 turns on memory logging (qset does not log)\n\
   For example:\n\
     testqset 10000\n\
 ";
 
 int error_count= 0;  /* Global error_count.  checkSetContents() keeps its own error count.  It exits on too many errors */
 
 /* Macros normally defined in geom.h */
 #define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
 
 /* Macros normally defined in user.h */
 
 #define realT double
 #define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *))))
 #define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
 #define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */
 
 /* Macros normally defined in QhullSet.h */
 
 
 /* Functions normally defined in usermem.h */
 
 void qh_exit(int exitcode) {
     exit(exitcode);
 } /* exit */
 
 void qh_free(void *mem) {
     free(mem);
 } /* free */
 
 void *qh_malloc(size_t size) {
     return malloc(size);
 } /* malloc */
 
 void    qh_errexit(int exitcode, void *f, void *r)
 {
     f= r; /* unused */
     qh_exit(exitcode);
 }
 
 void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... )
 {
     static int needs_cr= 0;  /* True if qh_fprintf needs a CR */
 
     size_t fmtlen= strlen(fmt);
     va_list args;
 
     if (!fp) {
         fprintf(stderr, "qh_fprintf: fp not defined for '%s'", fmt);
         qh_errexit(6232, NULL, NULL);
     }
     if(fmtlen>0){
         if(fmt[fmtlen-1]=='\n'){
             if(needs_cr && fmtlen>1){
                 fprintf(fp, "\n");
             }
             needs_cr= 0;
         }else{
             needs_cr= 1;
         }
     }
     if(msgcode>=6000 && msgcode<7000){
         fprintf(fp, "Error TQ%d ", msgcode);
     }
     va_start(args, fmt);
     vfprintf(fp, fmt, args);
     va_end(args);
 }
 
 /* Defined below in order of use */
 int main(int argc, char **argv);
 void readOptions(int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel);
 void setupMemory(int tracelevel, int numInts, int **intarray);
 
 void testSetappendSettruncate(int numInts, int *intarray, int checkEvery);
 void testSetdelSetadd(int numInts, int *intarray, int checkEvery);
 void testSetappendSet(int numInts, int *intarray, int checkEvery);
 void testSetcompactCopy(int numInts, int *intarray, int checkEvery);
 void testSetequalInEtc(int numInts, int *intarray, int checkEvery);
 void testSettemp(int numInts, int *intarray, int checkEvery);
 void testSetlastEtc(int numInts, int *intarray, int checkEvery);
 void testSetdelsortedEtc(int numInts, int *intarray, int checkEvery);
 
 int log_i(setT *set, const char *s, int i, int numInts, int checkEvery);
 void checkSetContents(const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC);
 
 int main(int argc, char **argv) {
     int *intarray= NULL;
     int numInts;
     int checkEvery= MAXint;
     int curlong, totlong;
     int traceLevel= 4; /* 4 normally, no tracing since qset does not log.  5 for memory tracing */
 
     readOptions(argc, argv, prompt, &numInts, &checkEvery, &traceLevel);
     setupMemory(traceLevel, numInts, &intarray);
 
     testSetappendSettruncate(numInts, intarray, checkEvery);
     testSetdelSetadd(numInts, intarray, checkEvery);
     testSetappendSet(numInts, intarray, checkEvery);
     testSetcompactCopy(numInts, intarray, checkEvery);
     testSetequalInEtc(numInts, intarray, checkEvery);
     testSettemp(numInts, intarray, checkEvery);
     testSetlastEtc(numInts, intarray, checkEvery);
     testSetdelsortedEtc(numInts, intarray, checkEvery);
     printf("\n\nNot testing qh_setduplicate and qh_setfree2.\n  These routines use heap-allocated set contents.  See qhull tests.\n");
 
     qh_memstatistics(stdout);
     qh_memfreeshort(&curlong, &totlong);
     if (curlong || totlong){
         qh_fprintf(stderr, 8043, "qh_memfreeshort: did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
         error_count++;
     }
     if(error_count){
         qh_fprintf(stderr, 8012, "testqset: %d errors\n\n", error_count);
         exit(1);
     }else{
         printf("testqset: OK\n\n");
     }
     return 0;
 }/*main*/
 
 void readOptions(int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel)
 {
     long numIntsArg;
     long checkEveryArg;
     char *endp;
     int isTracing= 0;
 
     if (argc < 2 || argc > 4) {
         printf(promptstr);
         exit(0);
     }
     numIntsArg= strtol(argv[1], &endp, 10);
     if(numIntsArg<1){
         qh_fprintf(stderr, 6301, "First argument should be 1 or greater.  Got '%s'\n", argv[1]);
         exit(1);
     }
     if(numIntsArg>MAXint){
         qh_fprintf(stderr, 6302, "qset does not currently support 64-bit ints.  Maximum count is %d\n", MAXint);
         exit(1);
     }
     *numInts= (int)numIntsArg;
 
     if(argc==3 && argv[2][0]=='T' && argv[2][1]=='5' ){
         isTracing= 1;
         *traceLevel= 5;
     }
     if(argc==4 || (argc==3 && !isTracing)){
         checkEveryArg= strtol(argv[2], &endp, 10);
         if(checkEveryArg<1){
             qh_fprintf(stderr, 6321, "checkEvery argument should be 1 or greater.  Got '%s'\n", argv[2]);
             exit(1);
         }
         if(checkEveryArg>MAXint){
             qh_fprintf(stderr, 6322, "qset does not currently support 64-bit ints.  Maximum checkEvery is %d\n", MAXint);
             exit(1);
         }
         if(argc==4){
             if(argv[3][0]=='T' && argv[3][1]=='5' ){
                 isTracing= 1;
                 *traceLevel= 5;
             }else{
                 qh_fprintf(stderr, 6242, "Optional third argument must be 'T5'.  Got '%s'\n", argv[3]);
                 exit(1);
             }
         }
         *checkEvery= (int)checkEveryArg;
     }
 }/*readOptions*/
 
 void setupMemory(int tracelevel, int numInts, int **intarray)
 {
     int i;
     if(numInts<0 || numInts*(int)sizeof(int)<0){
         qh_fprintf(stderr, 6303, "qset does not currently support 64-bit ints.  Integer overflow\n");
         exit(1);
     }
     *intarray= qh_malloc(numInts * sizeof(int));
     if(!*intarray){
         qh_fprintf(stderr, 6304, "Failed to allocate %d bytes of memory\n", numInts * sizeof(int));
         exit(1);
     }
     for(i= 0; i=2){
         isCheck= log_i(ints, "n", numInts/2, numInts, checkEvery);
         qh_settruncate(ints, numInts/2);
         checkSetContents("qh_settruncate by half", ints, numInts/2, 0, -1, -1);
     }
     isCheck= log_i(ints, "n", 0, numInts, checkEvery);
     qh_settruncate(ints, 0);
     checkSetContents("qh_settruncate", ints, 0, -1, -1, -1);
 
     qh_fprintf(stderr, 8003, "\n\nTesting qh_setappend2ndlast 0,0..%d.  Test 0", numInts-1);
     qh_setfree(&ints);
     ints= qh_setnew(4);
     qh_setappend(&ints, intarray+0);
     for(i= 0; i=2){
         isCheck= log_i(ints, "n", numInts/2, numInts, checkEvery);
         SETtruncate_(ints, numInts/2);
         checkSetContents("SETtruncate_ by half", ints, numInts/2, 0, -1, -1);
     }
     isCheck= log_i(ints, "n", 0, numInts, checkEvery);
     SETtruncate_(ints, 0);
     checkSetContents("SETtruncate_", ints, 0, -1, -1, -1);
 
     qh_setfree(&ints);
 }/*testSetappendSettruncate*/
 
 void testSetdelSetadd(int numInts, int *intarray, int checkEvery)
 {
     setT *ints=qh_setnew(1);
     int i,j, isCheck;
 
     qh_fprintf(stderr, 8003, "\n\nTesting qh_setdelnthsorted and qh_setaddnth 1..%d. Test", numInts-1);
     for(j=1; j3){
                 qh_setdelsorted(ints, intarray+i/2);
                 checkSetContents("qh_setdelsorted", ints, j-1, 0, i/2+1, -1);
                 qh_setaddsorted(&ints, intarray+i/2);
                 checkSetContents("qh_setaddsorted i/2", ints, j, 0, 0, -1);
             }
             qh_setdellast(ints);
             checkSetContents("qh_setdellast", ints, (j ? j-1 : 0), 0, -1, -1);
             if(j>0){
                 qh_setaddsorted(&ints, intarray+j-1);
                 checkSetContents("qh_setaddsorted j-1", ints, j, 0, -1, -1);
             }
             if(j>4){
                 qh_setdelnthsorted(ints, i/2);
                 if (checkEvery==1)
                   checkSetContents("qh_setdelnthsorted", ints, j-1, 0, i/2+1, -1);
                 /* FIXUP qh_setdelnth  move-to-front */
                 qh_setdelsorted(ints, intarray+i/2+1);
                 checkSetContents("qh_setdelsorted 2", ints, j-2, 0, i/2+2, -1);
                 qh_setaddsorted(&ints, intarray+i/2+1);
                 if (checkEvery==1)
                   checkSetContents("qh_setaddsorted i/2+1", ints, j-1, 0, i/2+1, -1);
                 qh_setaddsorted(&ints, intarray+i/2);
                 checkSetContents("qh_setaddsorted i/2 again", ints, j, 0, -1, -1);
             }
             qh_setfree(&ints2);
             ints2= qh_setcopy(ints, 0);
             qh_setcompact(ints);
             qh_setcompact(ints2);
             checkSetContents("qh_setcompact", ints, j, 0, 0, -1);
             checkSetContents("qh_setcompact 2", ints2, j, 0, 0, -1);
             qh_setcompact(ints);
             checkSetContents("qh_setcompact 3", ints, j, 0, 0, -1);
             qh_setfree(&ints2);
         }
     }
     qh_setfreelong(&ints);
     if(ints){
         qh_setfree(&ints); /* Was quick memory */
     }
 }/*testSetdelsortedEtc*/
 
 void testSetequalInEtc(int numInts, int *intarray, int checkEvery)
 {
     setT *ints= NULL;
     setT *ints2= NULL;
     setT *ints3= NULL;
     int i,j,n;
 
     qh_fprintf(stderr, 8019, "\n\nTesting qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..%d. Test", numInts-1);
     for(j=0; j0){
                 if(qh_setequal(ints, ints2)){
                     qh_fprintf(stderr, 6324, "testSetequalInEtc: non-empty set equal to empty set\n", j);
                     error_count++;
                 }
                 qh_setfree(&ints3);
                 ints3= qh_setcopy(ints, 0);
                 checkSetContents("qh_setreplace", ints3, j, 0, -1, -1);
                 qh_setreplace(ints3, intarray+j/2, intarray+j/2+1);
                 if(j==1){
                     checkSetContents("qh_setreplace 2", ints3, j, j/2+1, -1, -1);
                 }else if(j==2){
                     checkSetContents("qh_setreplace 3", ints3, j, 0, j/2+1, -1);
                 }else{
                     checkSetContents("qh_setreplace 3", ints3, j, 0, j/2+1, j/2+1);
                 }
                 if(qh_setequal(ints, ints3)){
                     qh_fprintf(stderr, 6325, "testSetequalInEtc: modified set equal to original set at %d/2\n", j);
                     error_count++;
                 }
                 if(!qh_setequal_except(ints, intarray+j/2, ints3, intarray+j/2+1)){
                     qh_fprintf(stderr, 6326, "qh_setequal_except: modified set not equal to original set except modified\n", j);
                     error_count++;
                 }
                 if(qh_setequal_except(ints, intarray+j/2, ints3, intarray)){
                     qh_fprintf(stderr, 6327, "qh_setequal_except: modified set equal to original set with wrong excepts\n", j);
                     error_count++;
                 }
                 if(!qh_setequal_skip(ints, j/2, ints3, j/2)){
                     qh_fprintf(stderr, 6328, "qh_setequal_skip: modified set not equal to original set except modified\n", j);
                     error_count++;
                 }
                 if(j>2 && qh_setequal_skip(ints, j/2, ints3, 0)){
                     qh_fprintf(stderr, 6329, "qh_setequal_skip: modified set equal to original set with wrong excepts\n", j);
                     error_count++;
                 }
                 if(intarray+j/2+1!=qh_setdel(ints3, intarray+j/2+1)){
                     qh_fprintf(stderr, 6330, "qh_setdel: failed to find added element\n", j);
                     error_count++;
                 }
                 checkSetContents("qh_setdel", ints3, j-1, 0, j-1, (j==1 ? -1 : j/2+1));  /* swaps last element with deleted element */
                 if(j>3){
                     qh_setdelnth(ints3, j/2); /* Delete at the same location as the original replace, for only one out-of-order element */
                     checkSetContents("qh_setdelnth", ints3, j-2, 0, j-2, (j==2 ? -1 : j/2+1));
                 }
                 if(qh_setin(ints3, intarray+j/2)){
                     qh_fprintf(stderr, 6331, "qh_setin: found deleted element\n");
                     error_count++;
                 }
                 if(j>4 && !qh_setin(ints3, intarray+1)){
                     qh_fprintf(stderr, 6332, "qh_setin: did not find second element\n");
                     error_count++;
                 }
                 if(j>4 && !qh_setin(ints3, intarray+j-2)){
                     qh_fprintf(stderr, 6333, "qh_setin: did not find last element\n");
                     error_count++;
                 }
                 if(-1!=qh_setindex(ints2, intarray)){
                     qh_fprintf(stderr, 6334, "qh_setindex: found element in empty set\n");
                     error_count++;
                 }
                 if(-1!=qh_setindex(ints3, intarray+j/2)){
                     qh_fprintf(stderr, 6335, "qh_setindex: found deleted element in set\n");
                     error_count++;
                 }
                 if(0!=qh_setindex(ints, intarray)){
                     qh_fprintf(stderr, 6336, "qh_setindex: did not find first in set\n");
                     error_count++;
                 }
                 if(j-1!=qh_setindex(ints, intarray+j-1)){
                     qh_fprintf(stderr, 6337, "qh_setindex: did not find last in set\n");
                     error_count++;
                 }
             }
             qh_setfree(&ints2);
         }
     }
     qh_setfree(&ints3);
     qh_setfreelong(&ints);
     if(ints){
         qh_setfree(&ints); /* Was quick memory */
     }
 }/*testSetequalInEtc*/
 
 
 void testSetlastEtc(int numInts, int *intarray, int checkEvery)
 {
     setT *ints= NULL;
     setT *ints2= NULL;
     int i,j,prepend;
 
     qh_fprintf(stderr, 8020, "\n\nTesting qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..%d. Test", numInts-1);
     for(j=0; j0){
                 if(intarray+j-1!=qh_setlast(ints)){
                     qh_fprintf(stderr, 6338, "qh_setlast: wrong last element\n");
                     error_count++;
                 }
                 prepend= (j<100 ? j/4 : 0);
                 ints2= qh_setnew_delnthsorted(ints, qh_setsize(ints), j/2, prepend);
                 if(qh_setsize(ints2)!=j+prepend-1){
                     qh_fprintf(stderr, 6345, "qh_setnew_delnthsorted: Expecting %d elements, got %d\n", j+prepend-1, qh_setsize(ints2));
                     error_count++;
                 }
                 /* Define prepended elements.  Otherwise qh_setdelnthsorted may fail */
                 for(i= 0; i2){
                     qh_setzero(ints2, j/2, j-1);  /* max size may be j-1 */
                     if(qh_setsize(ints2)!=j-1){
                         qh_fprintf(stderr, 6342, "qh_setzero: Expecting %d elements, got %d\n", j, qh_setsize(ints2));
                         error_count++;
                     }
                     qh_setcompact(ints2);
                     checkSetContents("qh_setzero", ints2, j/2, 0, -1, -1);
                 }
             }
             qh_setfree(&ints2);
         }
     }
     qh_setfreelong(&ints);
     if(ints){
         qh_setfree(&ints); /* Was quick memory */
     }
 }/*testSetlastEtc*/
 
 void testSettemp(int numInts, int *intarray, int checkEvery)
 {
     setT *ints= NULL;
     setT *ints2= NULL;
     setT *ints3= NULL;
     int i,j;
 
     qh_fprintf(stderr, 8021, "\n\nTesting qh_settemp* 0..%d. Test", numInts-1);
     for(j=0; j0){
                 qh_settemppush(ints);
                 ints3= qh_settemppop();
                 if(ints!=ints3){
                     qh_fprintf(stderr, 6343, "qh_settemppop: didn't pop the push\n");
                     error_count++;
                 }
             }
             qh_settempfree(&ints2);
         }
     }
     qh_setfreelong(&ints);
     if(ints){
         qh_setfree(&ints); /* Was quick memory */
     }
 }/*testSettemp*/
 
 /* Check that a set contains count elements
    Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
    Use -1 for missing ranges
    Returns -1 if should check results
 */
 int log_i(setT *set, const char *s, int i, int numInts, int checkEvery)
 {
     int j= i;
     int scale= 1;
     int e= 0;
     int *i2, **i2p;
 
     if(*s || checkEvery==1){
         if(i<10){
             qh_fprintf(stderr, 8004, " %s%d", s, i);
         }else{
             if(i==11 && checkEvery==1){
                 qh_fprintf(stderr, 8005, "\nResults after 10: ");
                 FOREACHint_(set){
                     qh_fprintf(stderr, 8006, " %d", *i2);
                 }
                 qh_fprintf(stderr, 8007, " Continue");
             }
             while((j= j/10)>=1){
                 scale *= 10;
                 e++;
             }
             if(i==numInts-1){
                 qh_fprintf(stderr, 8008, " %s%d", s, i);
             }else if(i==scale){
                 if(i<=1000){
                     qh_fprintf(stderr, 8010, " %s%d", s, i);
                 }else{
                     qh_fprintf(stderr, 8009, " %s1e%d", s, e);
                 }
             }
         }
     }
     if(i<1000 || i%checkEvery==0 || i== scale || i==numInts-1){
         return 1;
     }
     return 0;
 }/*log_i*/
 
 /* Check that a set contains count elements
    Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
    Use -1 for missing ranges
 */
 void checkSetContents(const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC)
 {
 
     i2T *i2, **i2p;
     int i2_i, i2_n;
     int prev= -1; /* avoid warning */
     int i;
     int first= -3;
     int second= -3;
     int rangeCount=1;
     int actualSize= 0;
 
     qh_setcheck(set, name, 0);
     if(set){
         SETreturnsize_(set, actualSize);  /* normally used only when speed is critical */
         if(*qh_setendpointer(set)!=NULL){
             qh_fprintf(stderr, 6344, "%s: qh_setendpointer(), 0x%x, is not NULL terminator of set 0x%x", name, qh_setendpointer(set), set);
             error_count++;
         }
     }
     if(actualSize!=qh_setsize(set)){
         qh_fprintf(stderr, 6305, "%s: SETreturnsize_() returned %d while qh_setsize() returns %d\n", name, actualSize, qh_setsize(set));
         error_count++;
     }else if(actualSize!=count){
         qh_fprintf(stderr, 6306, "%s: Expecting %d elements for set.  Got %d elements\n", name, count, actualSize);
         error_count++;
     }
     if(SETempty_(set)){
         if(count!=0){
             qh_fprintf(stderr, 6307, "%s: Got empty set instead of count %d, rangeA %d, rangeB %d, rangeC %d\n", name, count, rangeA, rangeB, rangeC);
             error_count++;
         }
     }else{
         /* Must be first, otherwise trips msvc 8 */
         i2T **p= SETaddr_(set, i2T);
         if(*p!=SETfirstt_(set, i2T)){
             qh_fprintf(stderr, 6309, "%s: SETaddr_(set, i2t) [%p] is not the same as SETfirst_(set) [%p]\n", name, SETaddr_(set, i2T), SETfirst_(set));
             error_count++;
         }
         first= *(int *)SETfirst_(set);
         if(SETfirst_(set)!=SETfirstt_(set, i2T)){
             qh_fprintf(stderr, 6308, "%s: SETfirst_(set) [%p] is not the same as SETfirstt_(set, i2T [%p]\n", name, SETfirst_(set), SETfirstt_(set, i2T));
             error_count++;
         }
         if(qh_setsize(set)>1){
             second= *(int *)SETsecond_(set);
             if(SETsecond_(set)!=SETsecondt_(set, i2T)){
                 qh_fprintf(stderr, 6310, "%s: SETsecond_(set) [%p] is not the same as SETsecondt_(set, i2T) [%p]\n", name, SETsecond_(set), SETsecondt_(set, i2T));
                 error_count++;
             }
         }
     }
     /* Test first run of ints in set*/
     i= 0;
     FOREACHint_(set){
         if(i2!=SETfirst_(set) && *i2!=prev+1){
             break;
         }
         prev= *i2;
         if(SETindex_(set, i2)!=i){
             qh_fprintf(stderr, 6311, "%s: Expecting SETIndex_(set, pointer-to-%d) to be %d.  Got %d\n", name, *i2, i, SETindex_(set, i2));
             error_count++;;
         }
         if(i2!=SETref_(i2)){
             qh_fprintf(stderr, 6312, "%s: SETref_(i2) [%p] does not point to i2 (the %d'th element)\n", name, SETref_(i2), i);
             error_count++;;
         }
         i++;
     }
     FOREACHint_i_(set){
         /* Must be first conditional, otherwise it trips up msvc 8 */
         i2T **p= SETelemaddr_(set, i2_i, i2T);
         if(i2!=*p){
             qh_fprintf(stderr, 6320, "%s: SETelemaddr_(set, %d, i2T) [%p] does not point to i2\n", name, i2_i, SETelemaddr_(set, i2_i, int));
             error_count++;;
         }
         if(i2_i==0){
             if(first!=*i2){
                 qh_fprintf(stderr, 6314, "%s: First element is %d instead of SETfirst %d\n", name, *i2, first);
                 error_count++;;
             }
             if(rangeA!=*i2){
                 qh_fprintf(stderr, 6315, "%s: starts with %d instead of rangeA %d\n", name, *i2, rangeA);
                 error_count++;;
             }
             prev= rangeA;
         }else{
             if(i2_i==1 && second!=*i2){
                 qh_fprintf(stderr, 6316, "%s: Second element is %d instead of SETsecond %d\n", name, *i2, second);
                 error_count++;;
             }
             if(prev+1==*i2){
                 prev++;
             }else{
                 if(*i2==rangeB){
                     prev= rangeB;
                     rangeB= -1;
                     rangeCount++;
                 }else if(rangeB==-1 && *i2==rangeC){
                     prev= rangeC;
                     rangeC= -1;
                     rangeCount++;
                 }else{
                     prev++;
                     qh_fprintf(stderr, 6317, "%s: Expecting %d'th element to be %d.  Got %d\n", name, i2_i, prev, *i2);
                     error_count++;
                 }
             }
         }
         if(i2!=SETelem_(set, i2_i)){
             qh_fprintf(stderr, 6318, "%s: SETelem_(set, %d) [%p] is not i2 [%p] (the %d'th element)\n", name, i2_i, SETelem_(set, i2_i), i2, i2_i);
             error_count++;;
         }
         if(SETelemt_(set, i2_i, i2T)!=SETelem_(set, i2_i)){   /* Normally SETelemt_ is used for generic sets */
             qh_fprintf(stderr, 6319, "%s: SETelemt_(set, %d, i2T) [%p] is not SETelem_(set, %d) [%p] (the %d'th element)\n", name, i2_i, SETelemt_(set, i2_i, int), i2_i, SETelem_(set, i2_i), i2_i);
             error_count++;;
         }
     }
     if(error_count>=MAXerrorCount){
         qh_fprintf(stderr, 8011, "testqset: Stop testing after %d errors\n", error_count);
         exit(1);
     }
 }/*checkSetContents*/
 
diff --git a/src/testqsetr/testqset_r.c b/src/testqsetr/testqset_r.c
index ed5a568..8d3e569 100644
--- a/src/testqsetr/testqset_r.c
+++ b/src/testqsetr/testqset_r.c
@@ -1,875 +1,879 @@
 /*
  ---------------------------------
 
    testset.c -- test qset.c and its use of mem.c
 
    The test sets are pointers to int.  Normally a set is a pointer to a type (e.g., facetT, ridgeT, etc.).
    For consistency in notation, an "int" is typedef'd to i2T
 
 Functions and macros from qset.h.  Counts occurrences in this test.  Does not correspond to thoroughness.
     qh_setaddsorted -- 4 tests
     qh_setaddnth -- 1 test
     qh_setappend -- 7 tests
     qh_setappend_set -- 1 test
     qh_setappend2ndlast -- 1 test
     qh_setcheck -- lots of tests
     qh_setcompact -- 7 tests
     qh_setcopy -- 3 tests
     qh_setdel -- 1 tests
     qh_setdellast -- 1 tests
     qh_setdelnth -- 2 tests
     qh_setdelnthsorted -- 2 tests
     qh_setdelsorted -- 1 test
     qh_setduplicate -- not testable here
     qh_setequal -- 4 tests
     qh_setequal_except -- 2 tests
     qh_setequal_skip -- 2 tests
     qh_setfree -- 11+ tests
     qh_setfree2 -- not testable here
     qh_setfreelong -- 2 tests
     qh_setin -- 3 tests
     qh_setindex -- 4 tests
     qh_setlarger -- 1 test
     qh_setlast -- 2 tests
     qh_setnew -- 6 tests
     qh_setnew_delnthsorted
     qh_setprint -- tested elsewhere
     qh_setreplace -- 1 test
     qh_setsize -- 9+ tests
     qh_settemp -- 2 tests
     qh_settempfree -- 1 test
     qh_settempfree_all -- 1 test
     qh_settemppop -- 1 test
     qh_settemppush -- 1 test
     qh_settruncate -- 3 tests
     qh_setunique -- 3 tests
     qh_setzero -- 1 test
     FOREACHint_ -- 2 test
     FOREACHint4_
     FOREACHint_i_ -- 1 test
     FOREACHintreverse_
     FOREACHintreverse12_
     FOREACHsetelement_ -- 1 test
     FOREACHsetelement_i_ -- 1 test
     FOREACHsetelementreverse_ -- 1 test
     FOREACHsetelementreverse12_ -- 1 test
     SETelem_ -- 3 tests
     SETelemaddr_ -- 2 tests
     SETelemt_ -- not tested (generic)
     SETempty_ -- 1 test
     SETfirst_ -- 4 tests
     SETfirstt_ -- 2 tests
     SETindex_ -- 2 tests
     SETref_ -- 2 tests
     SETreturnsize_ -- 2 tests
     SETsecond_ -- 1 test
     SETsecondt_ -- 2 tests
     SETtruncate_ -- 2 tests
+
+    Copyright (c) 2012-2015 C.B. Barber. All rights reserved.
+    $Id: //main/2011/qhull/src/testqsetr/testqset_r.c#3 $$Change: 1810 $
+    $DateTime: 2015/01/17 18:28:15 $$Author: bbarber $
 */
 
 #include 
 #include 
 #include 
 #include 
 
 #include "../libqhullr/qset_r.h"
 #include "../libqhullr/mem_r.h"
 #include "../libqhullr/libqhull_r.h"
 
 typedef int i2T;
 #define MAXerrorCount 100 /* quit after n errors */
 
 #define FOREACHint_( ints ) FOREACHsetelement_( i2T, ints, i2)
 #define FOREACHint4_( ints ) FOREACHsetelement_( i2T, ints, i4)
 #define FOREACHint_i_( qh, ints ) FOREACHsetelement_i_( qh, i2T, ints, i2)
 #define FOREACHintreverse_( qh, ints ) FOREACHsetelementreverse_( qh, i2T, ints, i2)
 #define FOREACHintreverse12_( ints ) FOREACHsetelementreverse12_( i2T, ints, i2)
 
 enum {
     MAXint= 0x7fffffff,
 };
 
 char prompt[]= "testqsetr N [M] [T5] -- Test reentrant qset_r.c and mem_r.c\n\
   Test qsets of 0..N integers with a check every M iterations (default ~log10)\n\
   Additional checking and logging if M is 1\n\
   T5 turns on memory logging (qset does not log)\n\
   For example:\n\
     testqsetr 10000\n\
 ";
 
 int error_count= 0;  /* Global error_count.  checkSetContents(qh) keeps its own error count.  It exits on too many errors */
 
 /* Macros normally defined in geom.h */
 #define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
 
 /* Macros normally defined in QhullSet.h */
 
 /* Functions normally defined in usermem.h */
 
 void qh_exit(int exitcode) {
     exit(exitcode);
 } /* exit */
 
 void qh_free(void *mem) {
     free(mem);
 } /* free */
 
 void *qh_malloc(size_t size) {
     return malloc(size);
 } /* malloc */
 
 void    qh_errexit(qhT *qh, int exitcode, facetT *f, ridgeT *r)
 {
     void *unused= f;
     unused= r; 
     unused= qh;
     qh_exit(exitcode);
 }
 
 void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... )
 {
     static int needs_cr= 0;  /* True if qh_fprintf needs a CR */
 
     size_t fmtlen= strlen(fmt);
     va_list args;
 
     if (!fp) {
         if(!qh)
             fprintf(stderr, "QH6241 qh_fprintf: fp and qh not defined for '%s'", fmt);
         else
             fprintf(stderr, "QH6232 qh_fprintf: fp is 0.  Was wrong qh_fprintf called for '%s'", fmt);
         qh_errexit(qh, 6232, NULL, NULL);
     }
     if(fmtlen>0){
         if(fmt[fmtlen-1]=='\n'){
             if(needs_cr && fmtlen>1){
                 fprintf(fp, "\n");
             }
             needs_cr= 0;
         }else{
             needs_cr= 1;
         }
     }
     if(msgcode>=6000 && msgcode<7000){
         fprintf(fp, "Error TQ%d ", msgcode);
     }
     va_start(args, fmt);
     vfprintf(fp, fmt, args);
     va_end(args);
 }
 
 /* Defined below in order of use */
 int main(int argc, char **argv);
 void readOptions(qhT *qh, int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel);
 void setupMemory(qhT *qh, int tracelevel, int numInts, int **intarray);
 
 void testSetappendSettruncate(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSetdelSetadd(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSetappendSet(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSetcompactCopy(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSetequalInEtc(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSettemp(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSetlastEtc(qhT *qh, int numInts, int *intarray, int checkEvery);
 void testSetdelsortedEtc(qhT *qh, int numInts, int *intarray, int checkEvery);
 
 int log_i(qhT *qh, setT *set, const char *s, int i, int numInts, int checkEvery);
 void checkSetContents(qhT *qh, const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC);
 
 int main(int argc, char **argv) {
     int *intarray= NULL;
     int numInts;
     int checkEvery= MAXint;
     int curlong, totlong;
     int traceLevel= 4; /* 4 normally, no tracing since qset does not log.  Option 'T5' for memory tracing */
     qhT qh_qh;
     qhT *qh= &qh_qh;
 
     readOptions(qh, argc, argv, prompt, &numInts, &checkEvery, &traceLevel);
     setupMemory(qh, traceLevel, numInts, &intarray);
 
     testSetappendSettruncate(qh, numInts, intarray, checkEvery);
     testSetdelSetadd(qh, numInts, intarray, checkEvery);
     testSetappendSet(qh, numInts, intarray, checkEvery);
     testSetcompactCopy(qh, numInts, intarray, checkEvery);
     testSetequalInEtc(qh, numInts, intarray, checkEvery);
     testSettemp(qh, numInts, intarray, checkEvery);
     testSetlastEtc(qh, numInts, intarray, checkEvery);
     testSetdelsortedEtc(qh, numInts, intarray, checkEvery);
     printf("\n\nNot testing qh_setduplicate and qh_setfree2.\n  These routines use heap-allocated set contents.  See qhull tests.\n");
 
     qh_memstatistics(qh, stdout);
     qh_memfreeshort(qh, &curlong, &totlong);
     if (curlong || totlong){
         qh_fprintf(qh, stderr, 8043, "qh_memfreeshort: did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
         error_count++;
     }
     if(error_count){
         qh_fprintf(qh, stderr, 8012, "testqset: %d errors\n\n", error_count);
         exit(1);
     }else{
         printf("testqset: OK\n\n");
     }
     return 0;
 }/*main*/
 
 void readOptions(qhT *qh, int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel)
 {
     long numIntsArg;
     long checkEveryArg;
     char *endp;
     int isTracing= 0;
 
     if (argc < 2 || argc > 4) {
         printf(promptstr);
         exit(0);
     }
     numIntsArg= strtol(argv[1], &endp, 10);
     if(numIntsArg<1){
         qh_fprintf(qh, stderr, 6301, "First argument should be 1 or greater.  Got '%s'\n", argv[1]);
         exit(1);
     }
     if(numIntsArg>MAXint){
         qh_fprintf(qh, stderr, 6302, "qset does not currently support 64-bit ints.  Maximum count is %d\n", MAXint);
         exit(1);
     }
     *numInts= (int)numIntsArg;
 
     if(argc==3 && argv[2][0]=='T' && argv[2][1]=='5' ){
         isTracing= 1;
         *traceLevel= 5;
     }
     if(argc==4 || (argc==3 && !isTracing)){
         checkEveryArg= strtol(argv[2], &endp, 10);
         if(checkEveryArg<1){
             qh_fprintf(qh, stderr, 6321, "checkEvery argument should be 1 or greater.  Got '%s'\n", argv[2]);
             exit(1);
         }
         if(checkEveryArg>MAXint){
             qh_fprintf(qh, stderr, 6322, "qset does not currently support 64-bit ints.  Maximum checkEvery is %d\n", MAXint);
             exit(1);
         }
         if(argc==4){
             if(argv[3][0]=='T' && argv[3][1]=='5' ){
                 isTracing= 1;
                 *traceLevel= 5;
             }else{
                 qh_fprintf(qh, stderr, 6242, "Optional third argument must be 'T5'.  Got '%s'\n", argv[3]);
                 exit(1);
             }
         }
         *checkEvery= (int)checkEveryArg;
     }
 }/*readOptions*/
 
 void setupMemory(qhT *qh, int tracelevel, int numInts, int **intarray)
 {
     int i;
     if(numInts<0 || numInts*(int)sizeof(int)<0){
         qh_fprintf(qh, stderr, 6303, "qset does not currently support 64-bit ints.  Integer overflow\n");
         exit(1);
     }
     *intarray= qh_malloc(numInts * sizeof(int));
     if(!*intarray){
         qh_fprintf(qh, stderr, 6304, "Failed to allocate %d bytes of memory\n", numInts * sizeof(int));
         exit(1);
     }
     for(i= 0; i=2){
         isCheck= log_i(qh, ints, "n", numInts/2, numInts, checkEvery);
         qh_settruncate(qh, ints, numInts/2);
         checkSetContents(qh, "qh_settruncate by half", ints, numInts/2, 0, -1, -1);
     }
     isCheck= log_i(qh, ints, "n", 0, numInts, checkEvery);
     qh_settruncate(qh, ints, 0);
     checkSetContents(qh, "qh_settruncate", ints, 0, -1, -1, -1);
 
     qh_fprintf(qh, stderr, 8003, "\n\nTesting qh_setappend2ndlast 0,0..%d.  Test 0", numInts-1);
     qh_setfree(qh, &ints);
     ints= qh_setnew(qh, 4);
     qh_setappend(qh, &ints, intarray+0);
     for(i= 0; i=2){
         isCheck= log_i(qh, ints, "n", numInts/2, numInts, checkEvery);
         SETtruncate_(ints, numInts/2);
         checkSetContents(qh, "SETtruncate_ by half", ints, numInts/2, 0, -1, -1);
     }
     isCheck= log_i(qh, ints, "n", 0, numInts, checkEvery);
     SETtruncate_(ints, 0);
     checkSetContents(qh, "SETtruncate_", ints, 0, -1, -1, -1);
 
     qh_setfree(qh, &ints);
 }/*testSetappendSettruncate*/
 
 void testSetdelSetadd(qhT *qh, int numInts, int *intarray, int checkEvery)
 {
     setT *ints=qh_setnew(qh, 1);
     int i,j, isCheck;
 
     qh_fprintf(qh, stderr, 8003, "\n\nTesting qh_setdelnthsorted and qh_setaddnth 1..%d. Test", numInts-1);
     for(j=1; j3){
                 qh_setdelsorted(ints, intarray+i/2);
                 checkSetContents(qh, "qh_setdelsorted", ints, j-1, 0, i/2+1, -1);
                 qh_setaddsorted(qh, &ints, intarray+i/2);
                 checkSetContents(qh, "qh_setaddsorted i/2", ints, j, 0, 0, -1);
             }
             qh_setdellast(ints);
             checkSetContents(qh, "qh_setdellast", ints, (j ? j-1 : 0), 0, -1, -1);
             if(j>0){
                 qh_setaddsorted(qh, &ints, intarray+j-1);
                 checkSetContents(qh, "qh_setaddsorted j-1", ints, j, 0, -1, -1);
             }
             if(j>4){
                 qh_setdelnthsorted(qh, ints, i/2);
                 if (checkEvery==1)
                   checkSetContents(qh, "qh_setdelnthsorted", ints, j-1, 0, i/2+1, -1);
                 /* FIXUP qh_setdelnth  move-to-front */
                 qh_setdelsorted(ints, intarray+i/2+1);
                 checkSetContents(qh, "qh_setdelsorted 2", ints, j-2, 0, i/2+2, -1);
                 qh_setaddsorted(qh, &ints, intarray+i/2+1);
                 if (checkEvery==1)
                   checkSetContents(qh, "qh_setaddsorted i/2+1", ints, j-1, 0, i/2+1, -1);
                 qh_setaddsorted(qh, &ints, intarray+i/2);
                 checkSetContents(qh, "qh_setaddsorted i/2 again", ints, j, 0, -1, -1);
             }
             qh_setfree(qh, &ints2);
             ints2= qh_setcopy(qh, ints, 0);
             qh_setcompact(qh, ints);
             qh_setcompact(qh, ints2);
             checkSetContents(qh, "qh_setcompact", ints, j, 0, 0, -1);
             checkSetContents(qh, "qh_setcompact 2", ints2, j, 0, 0, -1);
             qh_setcompact(qh, ints);
             checkSetContents(qh, "qh_setcompact 3", ints, j, 0, 0, -1);
             qh_setfree(qh, &ints2);
         }
     }
     qh_setfreelong(qh, &ints);
     if(ints){
         qh_setfree(qh, &ints); /* Was quick memory */
     }
 }/*testSetdelsortedEtc*/
 
 void testSetequalInEtc(qhT *qh, int numInts, int *intarray, int checkEvery)
 {
     setT *ints= NULL;
     setT *ints2= NULL;
     setT *ints3= NULL;
     int i,j,n;
 
     qh_fprintf(qh, stderr, 8019, "\n\nTesting qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..%d. Test", numInts-1);
     for(j=0; j0){
                 if(qh_setequal(ints, ints2)){
                     qh_fprintf(qh, stderr, 6324, "testSetequalInEtc: non-empty set equal to empty set\n", j);
                     error_count++;
                 }
                 qh_setfree(qh, &ints3);
                 ints3= qh_setcopy(qh, ints, 0);
                 checkSetContents(qh, "qh_setreplace", ints3, j, 0, -1, -1);
                 qh_setreplace(qh, ints3, intarray+j/2, intarray+j/2+1);
                 if(j==1){
                     checkSetContents(qh, "qh_setreplace 2", ints3, j, j/2+1, -1, -1);
                 }else if(j==2){
                     checkSetContents(qh, "qh_setreplace 3", ints3, j, 0, j/2+1, -1);
                 }else{
                     checkSetContents(qh, "qh_setreplace 3", ints3, j, 0, j/2+1, j/2+1);
                 }
                 if(qh_setequal(ints, ints3)){
                     qh_fprintf(qh, stderr, 6325, "testSetequalInEtc: modified set equal to original set at %d/2\n", j);
                     error_count++;
                 }
                 if(!qh_setequal_except(ints, intarray+j/2, ints3, intarray+j/2+1)){
                     qh_fprintf(qh, stderr, 6326, "qh_setequal_except: modified set not equal to original set except modified\n", j);
                     error_count++;
                 }
                 if(qh_setequal_except(ints, intarray+j/2, ints3, intarray)){
                     qh_fprintf(qh, stderr, 6327, "qh_setequal_except: modified set equal to original set with wrong excepts\n", j);
                     error_count++;
                 }
                 if(!qh_setequal_skip(ints, j/2, ints3, j/2)){
                     qh_fprintf(qh, stderr, 6328, "qh_setequal_skip: modified set not equal to original set except modified\n", j);
                     error_count++;
                 }
                 if(j>2 && qh_setequal_skip(ints, j/2, ints3, 0)){
                     qh_fprintf(qh, stderr, 6329, "qh_setequal_skip: modified set equal to original set with wrong excepts\n", j);
                     error_count++;
                 }
                 if(intarray+j/2+1!=qh_setdel(ints3, intarray+j/2+1)){
                     qh_fprintf(qh, stderr, 6330, "qh_setdel: failed to find added element\n", j);
                     error_count++;
                 }
                 checkSetContents(qh, "qh_setdel", ints3, j-1, 0, j-1, (j==1 ? -1 : j/2+1));  /* swaps last element with deleted element */
                 if(j>3){
                     qh_setdelnth(qh, ints3, j/2); /* Delete at the same location as the original replace, for only one out-of-order element */
                     checkSetContents(qh, "qh_setdelnth", ints3, j-2, 0, j-2, (j==2 ? -1 : j/2+1));
                 }
                 if(qh_setin(ints3, intarray+j/2)){
                     qh_fprintf(qh, stderr, 6331, "qh_setin: found deleted element\n");
                     error_count++;
                 }
                 if(j>4 && !qh_setin(ints3, intarray+1)){
                     qh_fprintf(qh, stderr, 6332, "qh_setin: did not find second element\n");
                     error_count++;
                 }
                 if(j>4 && !qh_setin(ints3, intarray+j-2)){
                     qh_fprintf(qh, stderr, 6333, "qh_setin: did not find last element\n");
                     error_count++;
                 }
                 if(-1!=qh_setindex(ints2, intarray)){
                     qh_fprintf(qh, stderr, 6334, "qh_setindex: found element in empty set\n");
                     error_count++;
                 }
                 if(-1!=qh_setindex(ints3, intarray+j/2)){
                     qh_fprintf(qh, stderr, 6335, "qh_setindex: found deleted element in set\n");
                     error_count++;
                 }
                 if(0!=qh_setindex(ints, intarray)){
                     qh_fprintf(qh, stderr, 6336, "qh_setindex: did not find first in set\n");
                     error_count++;
                 }
                 if(j-1!=qh_setindex(ints, intarray+j-1)){
                     qh_fprintf(qh, stderr, 6337, "qh_setindex: did not find last in set\n");
                     error_count++;
                 }
             }
             qh_setfree(qh, &ints2);
         }
     }
     qh_setfree(qh, &ints3);
     qh_setfreelong(qh, &ints);
     if(ints){
         qh_setfree(qh, &ints); /* Was quick memory */
     }
 }/*testSetequalInEtc*/
 
 
 void testSetlastEtc(qhT *qh, int numInts, int *intarray, int checkEvery)
 {
     setT *ints= NULL;
     setT *ints2= NULL;
     int i,j,prepend;
 
     qh_fprintf(qh, stderr, 8020, "\n\nTesting qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..%d. Test", numInts-1);
     for(j=0; j0){
                 if(intarray+j-1!=qh_setlast(ints)){
                     qh_fprintf(qh, stderr, 6338, "qh_setlast: wrong last element\n");
                     error_count++;
                 }
                 prepend= (j<100 ? j/4 : 0);
                 ints2= qh_setnew_delnthsorted(qh, ints, qh_setsize(qh, ints), j/2, prepend);
                 if(qh_setsize(qh, ints2)!=j+prepend-1){
                     qh_fprintf(qh, stderr, 6345, "qh_setnew_delnthsorted: Expecting %d elements, got %d\n", j+prepend-1, qh_setsize(qh, ints2));
                     error_count++;
                 }
                 /* Define prepended elements.  Otherwise qh_setdelnthsorted may fail */
                 for(i= 0; i2){
                     qh_setzero(qh, ints2, j/2, j-1);  /* max size may be j-1 */
                     if(qh_setsize(qh, ints2)!=j-1){
                         qh_fprintf(qh, stderr, 6342, "qh_setzero: Expecting %d elements, got %d\n", j, qh_setsize(qh, ints2));
                         error_count++;
                     }
                     qh_setcompact(qh, ints2);
                     checkSetContents(qh, "qh_setzero", ints2, j/2, 0, -1, -1);
                 }
             }
             qh_setfree(qh, &ints2);
         }
     }
     qh_setfreelong(qh, &ints);
     if(ints){
         qh_setfree(qh, &ints); /* Was quick memory */
     }
 }/*testSetlastEtc*/
 
 void testSettemp(qhT *qh, int numInts, int *intarray, int checkEvery)
 {
     setT *ints= NULL;
     setT *ints2= NULL;
     setT *ints3= NULL;
     int i,j;
 
     qh_fprintf(qh, stderr, 8021, "\n\nTesting qh_settemp* 0..%d. Test", numInts-1);
     for(j=0; j0){
                 qh_settemppush(qh, ints);
                 ints3= qh_settemppop(qh);
                 if(ints!=ints3){
                     qh_fprintf(qh, stderr, 6343, "qh_settemppop: didn't pop the push\n");
                     error_count++;
                 }
             }
             qh_settempfree(qh, &ints2);
         }
     }
     qh_setfreelong(qh, &ints);
     if(ints){
         qh_setfree(qh, &ints); /* Was quick memory */
     }
 }/*testSettemp*/
 
 /* Check that a set contains count elements
    Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
    Use -1 for missing ranges
    Returns -1 if should check results
 */
 int log_i(qhT *qh, setT *set, const char *s, int i, int numInts, int checkEvery)
 {
     int j= i;
     int scale= 1;
     int e= 0;
     int *i2, **i2p;
 
     if(*s || checkEvery==1){
         if(i<10){
             qh_fprintf(qh, stderr, 8004, " %s%d", s, i);
         }else{
             if(i==11 && checkEvery==1){
                 qh_fprintf(qh, stderr, 8005, "\nResults after 10: ");
                 FOREACHint_(set){
                     qh_fprintf(qh, stderr, 8006, " %d", *i2);
                 }
                 qh_fprintf(qh, stderr, 8007, " Continue");
             }
             while((j= j/10)>=1){
                 scale *= 10;
                 e++;
             }
             if(i==numInts-1){
                 qh_fprintf(qh, stderr, 8008, " %s%d", s, i);
             }else if(i==scale){
                 if(i<=1000){
                     qh_fprintf(qh, stderr, 8010, " %s%d", s, i);
                 }else{
                     qh_fprintf(qh, stderr, 8009, " %s1e%d", s, e);
                 }
             }
         }
     }
     if(i<1000 || i%checkEvery==0 || i== scale || i==numInts-1){
         return 1;
     }
     return 0;
 }/*log_i*/
 
 /* Check that a set contains count elements
    Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last
    Use -1 for missing ranges
 */
 void checkSetContents(qhT *qh, const char *name, setT *set, int count, int rangeA, int rangeB, int rangeC)
 {
 
     i2T *i2, **i2p;
     int i2_i, i2_n;
     int prev= -1; /* avoid warning */
     int i;
     int first= -3;
     int second= -3;
     int rangeCount=1;
     int actualSize= 0;
 
     qh_setcheck(qh, set, name, 0);
     if(set){
         SETreturnsize_(set, actualSize);  /* normally used only when speed is critical */
         if(*qh_setendpointer(set)!=NULL){
             qh_fprintf(qh, stderr, 6344, "%s: qh_setendpointer(set), 0x%x, is not NULL terminator of set 0x%x", name, qh_setendpointer(set), set);
             error_count++;
         }
     }
     if(actualSize!=qh_setsize(qh, set)){
         qh_fprintf(qh, stderr, 6305, "%s: SETreturnsize_(qh) returned %d while qh_setsize(qh) returns %d\n", name, actualSize, qh_setsize(qh, set));
         error_count++;
     }else if(actualSize!=count){
         qh_fprintf(qh, stderr, 6306, "%s: Expecting %d elements for set.  Got %d elements\n", name, count, actualSize);
         error_count++;
     }
     if(SETempty_(set)){
         if(count!=0){
             qh_fprintf(qh, stderr, 6307, "%s: Got empty set instead of count %d, rangeA %d, rangeB %d, rangeC %d\n", name, count, rangeA, rangeB, rangeC);
             error_count++;
         }
     }else{
         /* Must be first, otherwise trips msvc 8 */
         i2T **p= SETaddr_(set, i2T);
         if(*p!=SETfirstt_(set, i2T)){
             qh_fprintf(qh, stderr, 6309, "%s: SETaddr_(set, i2t) [%p] is not the same as SETfirst_(set) [%p]\n", name, SETaddr_(set, i2T), SETfirst_(set));
             error_count++;
         }
         first= *(int *)SETfirst_(set);
         if(SETfirst_(set)!=SETfirstt_(set, i2T)){
             qh_fprintf(qh, stderr, 6308, "%s: SETfirst_(set) [%p] is not the same as SETfirstt_(set, i2T [%p]\n", name, SETfirst_(set), SETfirstt_(set, i2T));
             error_count++;
         }
         if(qh_setsize(qh, set)>1){
             second= *(int *)SETsecond_(set);
             if(SETsecond_(set)!=SETsecondt_(set, i2T)){
                 qh_fprintf(qh, stderr, 6310, "%s: SETsecond_(set) [%p] is not the same as SETsecondt_(set, i2T) [%p]\n", name, SETsecond_(set), SETsecondt_(set, i2T));
                 error_count++;
             }
         }
     }
     /* Test first run of ints in set*/
     i= 0;
     FOREACHint_(set){
         if(i2!=SETfirst_(set) && *i2!=prev+1){
             break;
         }
         prev= *i2;
         if(SETindex_(set, i2)!=i){
             qh_fprintf(qh, stderr, 6311, "%s: Expecting SETindex_(set, pointer-to-%d) to be %d.  Got %d\n", name, *i2, i, SETindex_(set, i2));
             error_count++;;
         }
         if(i2!=SETref_(i2)){
             qh_fprintf(qh, stderr, 6312, "%s: SETref_(i2) [%p] does not point to i2 (the %d'th element)\n", name, SETref_(i2), i);
             error_count++;;
         }
         i++;
     }
     FOREACHint_i_(qh, set){
         /* Must be first conditional, otherwise it trips up msvc 8 */
         i2T **p= SETelemaddr_(set, i2_i, i2T);
         if(i2!=*p){
             qh_fprintf(qh, stderr, 6320, "%s: SETelemaddr_(set, %d, i2T) [%p] does not point to i2\n", name, i2_i, SETelemaddr_(set, i2_i, int));
             error_count++;;
         }
         if(i2_i==0){
             if(first!=*i2){
                 qh_fprintf(qh, stderr, 6314, "%s: First element is %d instead of SETfirst %d\n", name, *i2, first);
                 error_count++;;
             }
             if(rangeA!=*i2){
                 qh_fprintf(qh, stderr, 6315, "%s: starts with %d instead of rangeA %d\n", name, *i2, rangeA);
                 error_count++;;
             }
             prev= rangeA;
         }else{
             if(i2_i==1 && second!=*i2){
                 qh_fprintf(qh, stderr, 6316, "%s: Second element is %d instead of SETsecond %d\n", name, *i2, second);
                 error_count++;;
             }
             if(prev+1==*i2){
                 prev++;
             }else{
                 if(*i2==rangeB){
                     prev= rangeB;
                     rangeB= -1;
                     rangeCount++;
                 }else if(rangeB==-1 && *i2==rangeC){
                     prev= rangeC;
                     rangeC= -1;
                     rangeCount++;
                 }else{
                     prev++;
                     qh_fprintf(qh, stderr, 6317, "%s: Expecting %d'th element to be %d.  Got %d\n", name, i2_i, prev, *i2);
                     error_count++;
                 }
             }
         }
         if(i2!=SETelem_(set, i2_i)){
             qh_fprintf(qh, stderr, 6318, "%s: SETelem_(set, %d) [%p] is not i2 [%p] (the %d'th element)\n", name, i2_i, SETelem_(set, i2_i), i2, i2_i);
             error_count++;;
         }
         if(SETelemt_(set, i2_i, i2T)!=SETelem_(set, i2_i)){   /* Normally SETelemt_ is used for generic sets */
             qh_fprintf(qh, stderr, 6319, "%s: SETelemt_(set, %d, i2T) [%p] is not SETelem_(set, %d) [%p] (the %d'th element)\n", name, i2_i, SETelemt_(set, i2_i, int), i2_i, SETelem_(set, i2_i), i2_i);
             error_count++;;
         }
     }
     if(error_count>=MAXerrorCount){
         qh_fprintf(qh, stderr, 8011, "testqset: Stop testing after %d errors\n", error_count);
         exit(1);
     }
 }/*checkSetContents*/