Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Selten <michel@mselten.demon.nl>2003-12-06 22:17:13 +0300
committerMichel Selten <michel@mselten.demon.nl>2003-12-06 22:17:13 +0300
commit95732797bfd17ef2c670a2d3ab0f3afa1806ba53 (patch)
treefc4d40f7294c87defb2a184101709be53d0c9f6a /extern/qhull
parent581c0f232cb083da326657681fdcd4abe1d14c7a (diff)
Added the qhull sources to the repository.
These files are needed by Solid. I left out the generated Windows .exe files. If needed later on, I'll add them.
Diffstat (limited to 'extern/qhull')
-rwxr-xr-xextern/qhull/COPYING.txt37
-rwxr-xr-xextern/qhull/README.txt318
-rwxr-xr-xextern/qhull/REGISTER.txt37
-rwxr-xr-xextern/qhull/VisualC6/qhull.dsw29
-rwxr-xr-xextern/qhull/VisualC6/qhull/qhull.dsp180
-rwxr-xr-xextern/qhull/include/qhull/geom.h177
-rwxr-xr-xextern/qhull/include/qhull/io.h149
-rwxr-xr-xextern/qhull/include/qhull/mem.h174
-rwxr-xr-xextern/qhull/include/qhull/merge.h171
-rwxr-xr-xextern/qhull/include/qhull/poly.h290
-rwxr-xr-xextern/qhull/include/qhull/qhull.h1048
-rwxr-xr-xextern/qhull/include/qhull/qhull_a.h127
-rwxr-xr-xextern/qhull/include/qhull/qset.h468
-rwxr-xr-xextern/qhull/include/qhull/stat.h520
-rwxr-xr-xextern/qhull/include/qhull/user.h762
-rwxr-xr-xextern/qhull/src/Make-config.sh285
-rwxr-xr-xextern/qhull/src/Makefile.txt190
-rwxr-xr-xextern/qhull/src/geom.c1230
-rwxr-xr-xextern/qhull/src/geom.h177
-rwxr-xr-xextern/qhull/src/geom2.c2160
-rwxr-xr-xextern/qhull/src/global.c2018
-rwxr-xr-xextern/qhull/src/io.c4089
-rwxr-xr-xextern/qhull/src/io.h149
-rwxr-xr-xextern/qhull/src/mem.c447
-rwxr-xr-xextern/qhull/src/mem.h174
-rwxr-xr-xextern/qhull/src/merge.c3626
-rwxr-xr-xextern/qhull/src/merge.h171
-rwxr-xr-xextern/qhull/src/poly.c1180
-rwxr-xr-xextern/qhull/src/poly.h290
-rwxr-xr-xextern/qhull/src/poly2.c3070
-rwxr-xr-xextern/qhull/src/qconvex.c334
-rwxr-xr-xextern/qhull/src/qdelaun.c323
-rwxr-xr-xextern/qhull/src/qhalf.c324
-rwxr-xr-xextern/qhull/src/qhull.c1395
-rwxr-xr-xextern/qhull/src/qhull.h1048
-rwxr-xr-xextern/qhull/src/qhull_a.h127
-rwxr-xr-xextern/qhull/src/qhull_interface.cpp96
-rwxr-xr-xextern/qhull/src/qset.c1301
-rwxr-xr-xextern/qhull/src/qset.h468
-rwxr-xr-xextern/qhull/src/qvoronoi.c318
-rwxr-xr-xextern/qhull/src/rbox.c788
-rwxr-xr-xextern/qhull/src/stat.c700
-rwxr-xr-xextern/qhull/src/stat.h520
-rwxr-xr-xextern/qhull/src/unix.c376
-rwxr-xr-xextern/qhull/src/user.c324
-rwxr-xr-xextern/qhull/src/user.h762
-rwxr-xr-xextern/qhull/src/user_eg.c310
-rwxr-xr-xextern/qhull/src/user_eg2.c532
48 files changed, 33789 insertions, 0 deletions
diff --git a/extern/qhull/COPYING.txt b/extern/qhull/COPYING.txt
new file mode 100755
index 00000000000..1334eba6d0b
--- /dev/null
+++ b/extern/qhull/COPYING.txt
@@ -0,0 +1,37 @@
+ Qhull, Copyright (c) 1993-2002
+
+ The National Science and Technology Research Center for
+ Computation and Visualization of Geometric Structures
+ (The Geometry Center)
+ University of Minnesota
+ 400 Lind Hall
+ 207 Church Street S.E.
+ Minneapolis, MN 55455 USA
+
+ email: qhull@geom.umn.edu
+
+This software includes Qhull from The Geometry Center. Qhull is
+copyrighted as noted above. Qhull is free software and may be obtained
+via http from www.geom.umn.edu. It may be freely copied, modified,
+and redistributed under the following conditions:
+
+1. All copyright notices must remain intact in all files.
+
+2. A copy of this text file must be distributed along with any copies
+ of Qhull that you redistribute; this includes copies that you have
+ modified, or copies of programs or other software products that
+ include Qhull.
+
+3. If you modify Qhull, you must include a notice giving the
+ name of the person performing the modification, the date of
+ modification, and the reason for such modification.
+
+4. When distributing modified versions of Qhull, or other software
+ products that include Qhull, you must provide notice that the original
+ source code may be obtained as noted above.
+
+5. There is no warranty or other guarantee of fitness for Qhull, it is
+ provided solely "as is". Bug reports or fixes may be sent to
+ qhull_bug@geom.umn.edu; the authors may or may not act on them as
+ they desire.
+
diff --git a/extern/qhull/README.txt b/extern/qhull/README.txt
new file mode 100755
index 00000000000..9ef958a1f47
--- /dev/null
+++ b/extern/qhull/README.txt
@@ -0,0 +1,318 @@
+Name
+
+ qhull, rbox 2002.1 August 20, 2002
+
+Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection
+
+ Documentation:
+ html/index.htm
+
+ Available from:
+ <http://www.geom.umn.edu/software/qhull>
+ <http://savannah.gnu.org/projects/qhull>
+ <http://www.thesa.com/software/qhull>
+
+ Version 1 (simplicial only):
+ <http://www.geom.umn.edu/software/qhull/qhull-1.0.tar.gz>
+ <http://www.geom.umn.edu/software/qhull/qhull.sit.hqx>
+
+ News and a paper:
+ <http://www.geom.umn.edu/~bradb/qhull-news.html>
+ <http://www.geom.umn.edu/software/qhull/qhull-96.ps>
+
+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. <http://www.geomview.org>
+
+
+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.
+
+ Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt
+ before using or distributing Qhull.
+
+To contribute to Qhull
+
+ Qhull is on Savannah, http://savannah.gnu.org/projects/qhull/
+
+Qhull on Windows 95, 98, ME, NT, 2000, XP
+
+ The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaunay.exe,
+ qhalf.exe, qvoronoi.exe, documentation files, and source files.
+
+ To install Qhull:
+ - Unzip the files into a directory. You may use WinZip32 <www.hotfiles.com>
+ - Open a DOS window for the directory.
+ - In Windows 95, the DOS window needs improvement.
+ - Double-click on qhull\eg\qhull-go.bat to call doskey (arrow keys).
+ - Increase the size of the screen font to 8x12.
+ - If the text is too dim, fix the screen colors with shareware (e.g., crt.exe)
+ - If you use qhull a lot, consider using the Cygwin Unix shell,
+ Cygwin tools (http://sources.redhat.com/cygwin/)
+ - 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'.
+ - If an error occurs, Windows 95 sends the error to stdout instead of stderr
+ - use 'TO xxx' to send normal output to xxx and error output to stdout
+ - Browse the documentation: qhull\html\index.htm
+
+Compiling for Unix
+
+ The gzip file, qhull.tgz, contains documentation and source files for
+ qhull and rbox.
+
+ To unpack the gzip file
+ - tar zxf qhull.tgz
+ - cd qhull
+
+ Compiling with the Debian Make:[R. Laboissiere]
+ - cd src
+ - ./Make-config.sh
+ - cd ..
+ - configure
+ - make
+
+ Compiling with Makefile (i.e., Makefile.txt)
+ - cd src
+ - 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 is gcc-2.95.1, you need to set flag -fno-strict-aliasing.
+ - This flag is set by default for other versions [Karas, Krishnaswami]
+ - 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
+ - For gcc-2.95.1, you need to set flag -fno-strict-aliasing.
+ It is set by default for other versions of gcc [Karas, Krishnaswami]
+ - 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
+ - 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)
+ - to install the programs and their man pages:
+ - define MANDIR and BINDIR
+ - type 'make install'
+
+Compiling for Windows NT, 2000, XP with cygwin (www.cygwin.com)
+
+ - install cygwin with gcc, make, ar, and ln
+ - cd qhull/src
+ - make -f Makefile.txt
+
+Compiling for Windows 95, 98, NT, 2000, XP
+
+ Qhull compiles as a console application in Visual C++ 5.0 at warning
+ level 3.
+
+ Visual C++ quickstart for qhull.exe:
+ - create a "Win32 console application" called "qhull"
+ - add the following files:
+ geom.c geom2.c global.c io.c mem.c merge.c poly.c poly2.c qhull.c
+ qset.c stat.c unix.c user.c
+ - create a "Win32 console application" called "rbox"
+ - add rbox.c
+
+ Visual C++ quickstart for qhull library, qconvex.exe, etc.
+ - To simplify setting up lots of projects,
+ - create a temporary "Win32 console application" called "source"
+ - add all .c files from .../src/...
+ - In Tools::Options::Tab
+ Set tab size to 8 and indent size to 2
+
+ - create a "Win32 console application" called "rbox"
+ - move rbox.c from "qhull source"
+ - for Project:Settings..., Link
+ you only need the default libraries
+ - build the project
+
+ - create a "Win32 static library" called "library"
+ - move these files from "qhull source"
+ geom.c geom2.c global.c io.c mem.c merge.c poly.c poly2.c qhull.c
+ qset.c stat.c user.c
+ - set the library file (use the same for debug and release)
+ - build the project
+
+ - create a "Win32 console application" called "qhull"
+ - move unix.c from "qhull source"
+ - Set the library file in Project:Settings..., Link
+ - Qhull does not use other libraries
+
+ - create a "Win32 console application" called "qconvex"
+ - move qconvex.c from "qhull source"
+ - Set the library file in Project:Settings..., Link
+
+ - do the same for qdelaun.c, qhalf, qvoronoi.c, user_eg.c, user_eg2.c
+ - delete "qhull sources" since it is no longer needed
+ - Set the library file in Project:Settings..., Link
+ - use Project:Settings to make any changes
+ - use batch build to rebuild everything
+
+ 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.
+
+Compiling for the Power Macintosh
+
+ Qhull compiles for 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 for
+ Windows 95'. Instead of using SIOUX, Qhull may be embedded within an
+ application.
+
+ Version 1 is available for Macintosh computers by download of qhull.sit.hqx
+ It reads point coordinates from a standard file and returns output
+ to a standard file. There is no graphical output.
+
+
+Compiling for other machines
+
+ 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.
+
+ You may compile Qhull with a C++ compiler.
+
+
+Distributed files
+
+ README.txt // instructions for installing Qhull
+ REGISTER.txt // Qhull registration
+ COPYING.txt // copyright notice
+ Announce.txt // announcement
+ Changes.txt // change history for Qhull and rbox
+ qh-faq.htm // Frequently asked questions
+ qh-home.htm // Home page
+ qh-get.htm // Download page
+ html/index.htm // Manual
+ Makefile.txt // Makefile for Unix or cygwin 'make'
+ MBorland // Makefile for Borland C++/Win32
+ Make-config.sh // Create Debian configure and automake
+
+src/
+ rbox consists of:
+ rbox.exe // Win32 executable (.zip only)
+ rbox.htm // html manual
+ rbox.man // Unix man page
+ rbox.txt
+ rbox.c // source program
+
+ qhull consists of:
+ qhull.exe // Win32 executables (.zip only)
+ qconvex.exe
+ qdelaunay.exe
+ qhalf.exe
+ qvoronoi.exe
+ qhull-go.bat // DOS window
+ qconvex.htm // html manuals
+ qdelaun.htm
+ qdelau_f.htm
+ qhalf.htm
+ qvoronoi.htm
+ qvoron_f.htm
+ qh-eg.htm
+ qh-impre.htm
+ qh-in.htm
+ index.htm
+ qh-opt*.htm
+ qh-quick.htm
+ qh--4d.gif,etc. // images for manual
+ qhull.man // Unix man page
+ qhull.txt
+ q_eg // shell script for Geomview examples
+ q_egtest // shell script for Geomview test examples
+ q_test // shell script to test qhull
+
+ top-level source files:
+ src/index.htm // index to source files
+ qh-...htm // specific files
+ user.h // header file of user definable constants
+ qhull.h // header file for qhull
+ unix.c // Unix front end to qhull
+ qhull.c // Quickhull algorithm with partitioning
+ user.c // user re-definable functions
+ user_eg.c // example of incorporating qhull into a user program
+ user_eg2.c // more complex example
+ qhull_interface.cpp // call Qhull from C++
+
+ other source files:
+ qhull_a.h // include file for *.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
+ stat.c // statistics
+ stat.h
+
+Authors:
+
+ C. Bradford Barber Hannu Huhdanpaa
+ bradb@geom.umn.edu hannu@geom.umn.edu
+
+ c/o The Geometry Center
+ University of Minnesota
+ 400 Lind Hall
+ 207 Church Street S.E.
+ Minneapolis, MN 55455
+
+ This software was 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/extern/qhull/REGISTER.txt b/extern/qhull/REGISTER.txt
new file mode 100755
index 00000000000..767eb1c0cda
--- /dev/null
+++ b/extern/qhull/REGISTER.txt
@@ -0,0 +1,37 @@
+Dear User of Geometry Center Software:
+
+We would like to find out how you are using our software. Think of
+Geometry Center software as a new kind of shareware: you share your
+science and successes with us, and we share our software and support
+with you.
+
+If you use Geometry Center software, please send us a note telling
+us what you are doing with it.
+
+We need to know:
+
+ (1) What you are working on - an abstract of your work would be
+ fine.
+
+ (2) What Geometry Center software you use.
+
+ (3) How that software has helped you, for example, by increasing
+ your productivity or allowing you to do things you could not do
+ before. In particular, if you feel that Geometry Center
+ software has had a direct bearing on your work, please tell us
+ about this.
+
+We encourage you to cite the use of any Geometry Center software you
+have used in your publications.
+
+To cite Qhull, use
+
+ Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull
+ algorithm for convex hulls," ACM Trans. on Mathematical Software,
+ Dec 1996. http://www.geom.umn.edu/software/qhull
+
+Please send e-mail to
+
+ qhull@geom.umn.edu
+
+Thank you!
diff --git a/extern/qhull/VisualC6/qhull.dsw b/extern/qhull/VisualC6/qhull.dsw
new file mode 100755
index 00000000000..96c68d8e34c
--- /dev/null
+++ b/extern/qhull/VisualC6/qhull.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "qhull"=".\qhull\qhull.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/extern/qhull/VisualC6/qhull/qhull.dsp b/extern/qhull/VisualC6/qhull/qhull.dsp
new file mode 100755
index 00000000000..83160b2ecaa
--- /dev/null
+++ b/extern/qhull/VisualC6/qhull/qhull.dsp
@@ -0,0 +1,180 @@
+# Microsoft Developer Studio Project File - Name="qhull" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=qhull - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "qhull.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "qhull.mak" CFG="qhull - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "qhull - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "qhull - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "qhull - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "qhull - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "qhull - Win32 Release"
+# Name "qhull - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\src\geom.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\geom2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\global.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\io.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\merge.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\poly.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\poly2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\qhull.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\qset.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\stat.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\user.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\geom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\io.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\mem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\merge.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\poly.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\qhull.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\qhull_a.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\qset.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\stat.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\user.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/qhull/include/qhull/geom.h b/extern/qhull/include/qhull/geom.h
new file mode 100755
index 00000000000..32440cff56f
--- /dev/null
+++ b/extern/qhull/include/qhull/geom.h
@@ -0,0 +1,177 @@
+/*<html><pre> -<a href="qh-geom.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ geom.h
+ header file for geometric routines
+
+ see qh-geom.htm and geom.c
+
+ copyright (c) 1993-2002 The Geometry Center
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+/* ============ -macros- ======================== */
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="fabs_">-</a>
+
+ fabs_(a)
+ returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="fmax_">-</a>
+
+ fmax_(a,b)
+ returns the maximum value of a and b
+*/
+#define fmax_( a,b ) ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="fmin_">-</a>
+
+ fmin_(a,b)
+ returns the minimum value of a and b
+*/
+#define fmin_( a,b ) ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="maximize_">-</a>
+
+ maximize_(maxval, val)
+ set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) {if (( maxval ) < ( val )) ( maxval )= ( val );}
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="minimize_">-</a>
+
+ minimize_(minval, val)
+ set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) {if (( minval ) > ( val )) ( minval )= ( val );}
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="det2_">-</a>
+
+ det2_(a1, a2,
+ b1, b2)
+
+ compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="det3_">-</a>
+
+ 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 ) )
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="dX">-</a>
+
+ 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, char *string, realT **rows, int numrow, int numcol);
+void qh_printpoints (FILE *fp, 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);
+int qh_rand( void);
+void qh_srand( int seed);
+realT qh_randomfactor (void);
+void qh_randommatrix (realT *buffer, int dim, realT **row);
+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/extern/qhull/include/qhull/io.h b/extern/qhull/include/qhull/io.h
new file mode 100755
index 00000000000..351d56b3708
--- /dev/null
+++ b/extern/qhull/include/qhull/io.h
@@ -0,0 +1,149 @@
+/*<html><pre> -<a href="qh-io.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ io.h
+ declarations of Input/Output functions
+
+ see README, qhull.h and io.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+/*============ constants and flags ==================*/
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_MAXfirst">-</a>
+
+ qh_MAXfirst
+ maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst 200
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_MINradius">-</a>
+
+ qh_MINradius
+ min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_GEOMepsilon">-</a>
+
+ qh_GEOMepsilon
+ adjust outer planes for 'lines closer' and geomview roundoff.
+ This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_WHITESPACE">-</a>
+
+ qh_WHITESPACE
+ possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="RIDGE">-</a>
+
+ qh_RIDGE
+ to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+ qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="printvridgeT">-</a>
+
+ printvridgeT
+ prints results of qh_printvdiagram
+
+ see:
+ <a href="io.c#printvridge">qh_printvridge</a> for an example
+*/
+typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+void dfacet( unsigned id);
+void dvertex( unsigned id);
+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_printafacet(FILE *fp, int format, facetT *facet, boolT printall);
+void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void qh_printcenter (FILE *fp, int format, char *string, facetT *facet);
+void qh_printcentrum (FILE *fp, facetT *facet, realT radius);
+void qh_printend (FILE *fp, int 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, int printall);
+void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void qh_printfacet(FILE *fp, facetT *facet);
+void qh_printfacet2math(FILE *fp, facetT *facet, 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, 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, int 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, int format);
+void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format);
+void qh_printfacetheader(FILE *fp, facetT *facet);
+void qh_printfacetridges(FILE *fp, facetT *facet);
+void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void qh_printhelp_degenerate(FILE *fp);
+void qh_printhelp_singular(FILE *fp);
+void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+ setT *vertices, realT color[3]);
+void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void qh_printpoint(FILE *fp, char *string, pointT *point);
+void qh_printpointid(FILE *fp, 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, int 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, int 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, char* string, facetT *facetlist,
+ setT *facets, boolT printall);
+void qh_printvertices (FILE *fp, char* string, setT *vertices);
+void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void qh_printvoronoi (FILE *fp, int 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_projectdim3 (pointT *source, pointT *destination);
+int qh_readfeasible (int dim, char *remainder);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+void qh_setfeasible (int dim);
+boolT qh_skipfacet(facetT *facet);
+
+#endif /* qhDEFio */
diff --git a/extern/qhull/include/qhull/mem.h b/extern/qhull/include/qhull/mem.h
new file mode 100755
index 00000000000..e9ebd1bb9bc
--- /dev/null
+++ b/extern/qhull/include/qhull/mem.h
@@ -0,0 +1,174 @@
+/*<html><pre> -<a href="qh-mem.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="NOmem">-</a>
+
+ 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@geom.umn.edu. If this can
+ not be done, define qh_NOmem to use malloc/free instead.
+
+ #define qh_NOmem
+*/
+
+/*-------------------------------------------
+ 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 <a href="user.h#MEMalign">qh_MEMalign</a> in user.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4 /* matches qh_ERRmem in qhull.h */
+#define qhmem_ERRqhull 5 /* matches qh_ERRqhull in qhull.h */
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="ptr_intT">-</a>
+
+ ptr_intT
+ for casting a void* to an integer-type
+
+ notes:
+ On 64-bit machines, a pointer may be larger than an 'int'.
+ qh_meminit() checks that 'long' holds a 'void*'
+*/
+typedef unsigned long ptr_intT;
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="qhmemT">-</a>
+
+ 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;
+
+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 free memory in bytes */
+ void *tempstack; /* stack of temporary memory, managed by users */
+ FILE *ferr; /* file for reporting errors */
+ int IStracing; /* =5 if tracing memory allocations */
+ int cntquick; /* count of quick allocations */
+ /* remove statistics doesn't effect speed */
+ int cntshort; /* count of short allocations */
+ int cntlong; /* count of long allocations */
+ int curlong; /* current count of inuse, long allocations */
+ int freeshort; /* count of short memfrees */
+ int freelong; /* count of long memfrees */
+ int totshort; /* total size of short allocations */
+ int totlong; /* total size of long allocations */
+ int maxlong; /* maximum totlong */
+ int cntlarger; /* count of setlarger's */
+ int totlarger; /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="memalloc_">-</a>
+
+ qh_memalloc_(size, object, type)
+ returns object of size bytes
+ assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#ifdef qh_NOmem
+#define qh_memalloc_(size, freelistp, object, type) {\
+ object= (type*)qh_memalloc (size); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(size, freelistp, object, type) {\
+ freelistp= qhmem.freelists + qhmem.indextable[size];\
+ if ((object= (type*)*freelistp)) {\
+ qhmem.cntquick++; \
+ *freelistp= *((void **)*freelistp);\
+ }else object= (type*)qh_memalloc (size);}
+#endif
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="memfree_">-</a>
+
+ qh_memfree_(object, size)
+ free up an object
+
+ notes:
+ object may be NULL
+ assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+#ifdef qh_NOmem
+#define qh_memfree_(object, size, freelistp) {\
+ qh_memfree (object, size); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(object, size, freelistp) {\
+ if (object) { \
+ qhmem .freeshort++;\
+ freelistp= qhmem.freelists + qhmem.indextable[size];\
+ *((void **)object)= *freelistp;\
+ *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+void *qh_memalloc(int insize);
+void qh_memfree (void *object, int size);
+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);
+
+#endif /* qhDEFmem */
diff --git a/extern/qhull/include/qhull/merge.h b/extern/qhull/include/qhull/merge.h
new file mode 100755
index 00000000000..7fc2afa5967
--- /dev/null
+++ b/extern/qhull/include/qhull/merge.h
@@ -0,0 +1,171 @@
+/*<html><pre> -<a href="qh-merge.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ merge.h
+ header file for merge.c
+
+ see qh-merge.htm and merge.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+
+/*============ -constants- ==============*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_ANGLEredundant">-</a>
+
+ qh_ANGLEredundant
+ indicates redundant merge in mergeT->angle
+*/
+#define qh_ANGLEredundant 6.0
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_ANGLEdegen">-</a>
+
+ qh_ANGLEdegen
+ indicates degenerate facet in mergeT->angle
+*/
+#define qh_ANGLEdegen 5.0
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_ANGLEconcave">-</a>
+
+ 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
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="MRG">-</a>
+
+ 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 (not enough neighbors) facet1 == facet2 */
+ MRGredundant, /* redundant facet (vertex subset) */
+ /* merge_degenredundant assumes degen < redundant */
+ MRGmirror, /* mirror facet from qh_triangulate */
+ ENDmrg
+} mergeType;
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_MERGEapex">-</a>
+
+ qh_MERGEapex
+ flag for qh_mergefacet() to indicate an apex merge
+*/
+#define qh_MERGEapex True
+
+/*============ -structures- ====================*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="mergeT">-</a>
+
+ 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- =========================*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="FOREACHmerge_">-</a>
+
+ 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 <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#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 (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);
+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/extern/qhull/include/qhull/poly.h b/extern/qhull/include/qhull/poly.h
new file mode 100755
index 00000000000..294ec9527fc
--- /dev/null
+++ b/extern/qhull/include/qhull/poly.h
@@ -0,0 +1,290 @@
+/*<html><pre> -<a href="qh-poly.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ poly.h
+ header file for poly.c and poly2.c
+
+ see qh-poly.htm, qhull.h and poly.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+/*=============== constants ========================== */
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="ALGORITHMfault">-</a>
+
+ ALGORITHMfault
+ use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="DATAfault">-</a>
+
+ DATAfault
+ use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="DUPLICATEridge">-</a>
+
+ 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
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="MERGEridge">-</a>
+
+ 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- =========================*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLfacet_">-</a>
+
+ 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 )
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLnew_facets">-</a>
+
+ 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 )
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLvertex_">-</a>
+
+ 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 )
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLvisible_facets">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLsame_">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLsame_cycle_">-</a>
+
+ 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))
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHneighborA_">-</a>
+
+ 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:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHneighborA_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvisible_">-</a>
+
+ FOREACHvisible_( facets ) { ... }
+ assign 'visible' to each facet in facets
+
+ notes:
+ uses 'facetT *facet, *facetp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHnewfacet_">-</a>
+
+ FOREACHnewfacet_( facets ) { ... }
+ assign 'newfacet' to each facet in facets
+
+ notes:
+ uses 'facetT *newfacet, *newfacetp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertexA_">-</a>
+
+ FOREACHvertexA_( vertices ) { ... }
+ assign 'vertexA' to each vertex in vertices
+
+ notes:
+ uses 'vertexT *vertexA, *vertexAp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertexreverse12_">-</a>
+
+ FOREACHvertexreverse12_( vertices ) { ... }
+ assign 'vertex' to each vertex in vertices
+ reverse order of first two vertices
+
+ notes:
+ uses 'vertexT *vertex, *vertexp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#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);
+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);
+unsigned 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, unsigned 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_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/extern/qhull/include/qhull/qhull.h b/extern/qhull/include/qhull/qhull.h
new file mode 100755
index 00000000000..896ec1e9c18
--- /dev/null
+++ b/extern/qhull/include/qhull/qhull.h
@@ -0,0 +1,1048 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qhull.h
+ user-level header file for using qhull.a library
+
+ see qh-qhull.htm, qhull_a.h
+
+ copyright (c) 1993-2002, The Geometry Center
+
+ 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 qhull.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 qhull.h
+
+ recompile qhull if you change this file
+*/
+
+#ifndef qhDEFqhull
+#define qhDEFqhull 1
+
+/*=========================== -included files ==============*/
+
+#include <setjmp.h>
+#include <float.h>
+#include <time.h>
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <Desk.h>
+#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 qhull.h
+#endif
+#endif
+#endif
+
+#include "user.h" /* user defineable constants */
+
+/*============ constants and basic types ====================*/
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_VERSION">-</a>
+
+ qh_VERSION
+ version string by year and date
+
+ the revision increases on code changes only
+
+ notes:
+ change date: Changes.txt, Announce.txt, README.txt, qhull.man
+ qhull-news.html, Eudora signatures,
+ change version: README.txt, qhull.html, file_id.diz, Makefile
+ change year: Copying.txt
+ check download size
+ recompile user_eg.c, rbox.c, qhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c
+ make copy of qhull-news.html as qh-news.htm
+*/
+
+#define qh_VERSION "2002.1 2002/8/20"
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="coordT">-</a>
+
+ coordT
+ coordinates and coefficients are stored as realT (i.e., double)
+
+ notes:
+ 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
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="pointT">-</a>
+
+ pointT
+ a point is an array of DIM3 coordinates
+*/
+#define pointT coordT
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="flagT">-</a>
+
+ flagT
+ Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="boolT">-</a>
+
+ boolT
+ boolean value, either True or False
+
+ notes:
+ needed for portability
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="CENTERtype">-</a>
+
+ qh_CENTER
+ to distinguish facet->center
+*/
+typedef enum
+{
+ qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
+}
+qh_CENTER;
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_PRINT">-</a>
+
+ qh_PRINT
+ output formats for printing (qh.PRINTout).
+ 'Fa' 'FV' 'Fc' 'FC'
+
+
+ notes:
+ some of these names are similar to qh 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, /* 'n' 'Fo' 'i' 'm' '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;
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_ALL">-</a>
+
+ 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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_ERR">-</a>
+
+ qh_ERR
+ Qhull exit codes, for indicating errors
+*/
+#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 */
+
+/* ============ -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
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="facetT">-</a>
+
+ 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 defines ridge */
+ 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) */
+};
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="ridgeT">-</a>
+
+ ridgeT
+ defines a ridge
+
+ notes:
+ a ridge is DIM3-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 */
+ 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 */
+};
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="vertexT">-</a>
+
+ 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; /* for use with qh vertex_visit */
+ unsigned id:24; /* unique identifier, =>room for 8 flags */
+ flagT seen:1; /* used to perform operations only once */
+ flagT seen2:1; /* another seen flag */
+ 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 ============================*/
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh">-</a>
+
+ qh
+ all global variables for qhull are in qh, qhmem, and qhstat
+
+ notes:
+ qhmem is defined in mem.h and qhstat is defined in stat.h
+ access to qh_qh is via the "qh" macro. See qh_QHpointer in user.h
+*/
+typedef struct qhT qhT;
+#if qh_QHpointer
+#define qh qh_qh->
+extern qhT *qh_qh; /* allocated in global.c */
+#else
+#define qh qh_qh.
+extern qhT qh_qh;
+#endif
+
+struct qhT {
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-const">-</a>
+
+ 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 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 */
+ 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 (not 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 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 */
+ 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 before qh_initbuild */
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-prec">-</a>
+
+ 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 */
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-intern">-</a>
+
+ qh internal constants
+ internal constants for Qhull
+*/
+ char qhull[sizeof("qhull")]; /* for checking ownership */
+ void *old_stat; /* pointer to saved qh_qhstat, qh_save_qhull */
+ 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) */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-lists">-</a>
+
+ 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; /* ID of next, new ridge from newridge() */
+ unsigned vertex_id; /* ID of next, new vertex from newvertex() */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-var">-</a>
+
+ 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 */
+ 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 */
+ realT totvol; /* 'FA': total volume computed by qh_getarea */
+ unsigned int visit_id; /* unique ID for searching neighborhoods, */
+ unsigned int vertex_visit; /* unique ID for searching vertices */
+ boolT ZEROall_ok; /* True if qh_checkzero always succeeds */
+ boolT WAScoplanar; /* True if qh_partitioncoplanar (qh_check_maxout) */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-set">-</a>
+
+ 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 (first is qh interior_point) */
+ setT *del_vertices; /* vertices to partition and delete with visible
+ facets. Have deleted set for checkfacet */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-buf">-</a>
+
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-static">-</a>
+
+ 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 errexit (prevents duplicate calls */
+ boolT firstcentrum; /* for qh_printcentrum */
+ 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 */
+ boolT old_randomdist; /* save RANDOMdist when io, tracing, or statistics */
+ int ridgeoutnum; /* number of ridges in 4OFF output */
+ void *old_qhstat; /* for saving qh_qhstat in save_qhull() */
+ setT *old_tempstack; /* for saving qhmem.tempstack in save_qhull */
+ setT *coplanarset; /* set of coplanar facets for searching qh_findbesthorizon() */
+};
+
+/*=========== -macros- =========================*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="otherfacet_">-</a>
+
+ otherfacet_(ridge, facet)
+ return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+ (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="getid_">-</a>
+
+ getid_(p)
+ return ID for facet, ridge, or vertex
+ return MAXINT if NULL (-1 causes type conversion error )
+*/
+#define getid_(p) ((p) ? (p)->id : -1)
+
+/*============== FORALL macros ===================*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLfacets">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLpoints">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLpoint_">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLvertices">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHfacet_">-</a>
+
+ FOREACHfacet_( facets ) { ... }
+ assign 'facet' to each facet in facets
+
+ declare:
+ facetT *facet, **facetp;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHfacet_(facets) FOREACHsetelement_(facetT, facets, facet)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHneighbor_">-</a>
+
+ 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:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHneighbor_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHpoint_">-</a>
+
+ FOREACHpoint_( points ) { ... }
+ assign 'point' to each point in points set
+
+ declare:
+ pointT *point, **pointp;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHpoint_(points) FOREACHsetelement_(pointT, points, point)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHridge_">-</a>
+
+ FOREACHridge_( ridges ) { ... }
+ assign 'ridge' to each ridge in ridges set
+
+ declare:
+ ridgeT *ridge, **ridgep;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHridge_(ridges) FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertex_">-</a>
+
+ FOREACHvertex_( vertices ) { ... }
+ assign 'vertex' to each vertex in vertices set
+
+ declare:
+ vertexT *vertex, **vertexp;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHfacet_i_">-</a>
+
+ FOREACHfacet_i_( facets ) { ... }
+ assign 'facet' and 'facet_i' for each facet in facets set
+
+ declare:
+ facetT *facet;
+ int facet_n, facet_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHfacet_i_(facets) FOREACHsetelement_i_(facetT, facets, facet)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHneighbor_i_">-</a>
+
+ 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:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHneighbor_i_(facet) FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHpoint_i_">-</a>
+
+ FOREACHpoint_i_( points ) { ... }
+ assign 'point' and 'point_i' for each point in points set
+
+ declare:
+ pointT *point;
+ int point_n, point_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHpoint_i_(points) FOREACHsetelement_i_(pointT, points, point)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHridge_i_">-</a>
+
+ FOREACHridge_i_( ridges ) { ... }
+ assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+ declare:
+ ridgeT *ridge;
+ int ridge_n, ridge_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHridge_i_(ridges) FOREACHsetelement_i_(ridgeT, ridges, ridge)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertex_i_">-</a>
+
+ FOREACHvertex_i_( vertices ) { ... }
+ assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+ declare:
+ vertexT *vertex;
+ int vertex_n, vertex_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+ */
+#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
+
+/********* -qhull.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(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_user_memsizes (void);
+
+/***** -geom.c/geom2.c prototypes (duplicated from geom.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_freebuffers (void);
+void qh_freeqhull (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_start (FILE *infile, FILE *outfile, FILE *errfile);
+void qh_initthresholds (char *command);
+void qh_option (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 dfacet( unsigned id);
+void dvertex( unsigned id);
+void qh_printneighborhood (FILE *fp, int 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*/);
+
+/********* -stat.c prototypes (duplicated from stat.h) **********************/
+
+void qh_collectstatistics (void);
+void qh_printallstatistics (FILE *fp, char *string);
+
+#endif /* qhDEFqhull */
diff --git a/extern/qhull/include/qhull/qhull_a.h b/extern/qhull/include/qhull/qhull_a.h
new file mode 100755
index 00000000000..d4e69b071be
--- /dev/null
+++ b/extern/qhull/include/qhull/qhull_a.h
@@ -0,0 +1,127 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qhull_a.h
+ all header files for compiling qhull
+
+ see qh-qhull.htm
+
+ see qhull.h for user-level definitions
+
+ see user.h for user-defineable constants
+
+ defines internal functions for qhull.c global.c
+
+ copyright (c) 1993-2002, The Geometry Center
+
+ 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <math.h>
+#include <float.h> /* some compilers will not need float.h */
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+/*** uncomment here and qset.c
+ if string.h does not define memcpy()
+#include <memory.h>
+*/
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+#include "geom.h"
+#include "merge.h"
+#include "poly.h"
+#include "io.h"
+#include "stat.h"
+
+#if qh_CLOCKtype == 2 /* defined in user.h from qhull.h */
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+#endif
+
+#ifdef _MSC_VER /* Microsoft Visual C++ */
+#pragma warning( disable : 4056) /* float constant expression. Looks like a compiler bug */
+#pragma warning( disable : 4146) /* unary minus applied to unsigned type */
+#pragma warning( disable : 4244) /* conversion from 'unsigned long' to 'real' */
+#pragma warning( disable : 4305) /* conversion from 'const double' to 'float' */
+#endif
+
+/* ======= -macros- =========== */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="traceN">-</a>
+
+ traceN((fp.ferr, "format\n", vars));
+ calls fprintf if qh.IStracing >= N
+
+ notes:
+ removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh IStracing) fprintf args;}
+#define trace1(args) {if (qh IStracing >= 1) fprintf args;}
+#define trace2(args) {if (qh IStracing >= 2) fprintf args;}
+#define trace3(args) {if (qh IStracing >= 3) fprintf args;}
+#define trace4(args) {if (qh IStracing >= 4) fprintf args;}
+#define trace5(args) {if (qh IStracing >= 5) 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 */
+
+/***** -qhull.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 (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);
+int qh_strtol (const char *s, char **endp);
+double qh_strtod (const char *s, char **endp);
+
+/***** -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/extern/qhull/include/qhull/qset.h b/extern/qhull/include/qhull/qset.h
new file mode 100755
index 00000000000..6c0ff758de4
--- /dev/null
+++ b/extern/qhull/include/qhull/qset.h
@@ -0,0 +1,468 @@
+/*<html><pre> -<a href="qh-set.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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-2002, The Geometry Center
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT; /* a set is a sorted or unsorted array of pointers */
+#endif
+
+/*-<a href="qh-set.htm#TOC"
+>----------------------------------------</a><a name="setT">-</a>
+
+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- =========================*/
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="SETelemsize">-</a>
+
+ SETelemsize
+ size of a set element in bytes
+*/
+#define SETelemsize sizeof(setelemT)
+
+
+/*=========== -macros- =========================*/
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHsetelement_">-</a>
+
+ 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++);)
+
+/*-<a href="qh-set.htm#TOC"
+ >----------------------------------------</a><a name="FOREACHsetelement_i_">-</a>
+
+ 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) )
+
+/*-<a href="qh-set.htm#TOC"
+ >--------------------------------------</a><a name="FOREACHsetelementreverse_">-</a>
+
+ 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))
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHsetelementreverse12_">-</a>
+
+ 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++))
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHelem_">-</a>
+
+ 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)
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHset_">-</a>
+
+ 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)
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------------</a><a name="SETindex_">-</a>
+
+ SETindex_( set, elem )
+ return index of elem in set
+
+ notes:
+ for use with FOREACH iteration
+
+ example:
+ i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((void **)elem##p - (void **)&(set)->e[1].p)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETref_">-</a>
+
+ SETref_( elem )
+ l.h.s. for modifying the current element in a FOREACH iteration
+
+ example:
+ SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETelem_">-</a>
+
+ 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)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETelemt_">-</a>
+
+ 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))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETelemaddr_">-</a>
+
+ 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)))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETfirst_">-</a>
+
+ SETfirst_(set)
+ return first element of set
+
+*/
+#define SETfirst_(set) ((set)->e[0].p)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETfirstt_">-</a>
+
+ SETfirstt_(set, type)
+ return first element of set as a type
+
+*/
+#define SETfirstt_(set, type) ((type*)((set)->e[0].p))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETsecond_">-</a>
+
+ SETsecond_(set)
+ return second element of set
+
+*/
+#define SETsecond_(set) ((set)->e[1].p)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETsecondt_">-</a>
+
+ SETsecondt_(set, type)
+ return second element of set as a type
+*/
+#define SETsecondt_(set, type) ((type*)((set)->e[1].p))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETaddr_">-</a>
+
+ SETaddr_(set, type)
+ return address of set's elements
+*/
+#define SETaddr_(set,type) ((type **)(&((set)->e[0].p)))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETreturnsize_">-</a>
+
+ 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))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETempty_">-</a>
+
+ SETempty_(set)
+ return true (1) if set is empty
+
+ notes:
+ set may be NULL
+*/
+#define SETempty_(set) (!set || (SETfirst_(set) ? 0:1))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETtruncate_">-</a>
+
+ SETtruncate_(set)
+ return first element of set
+
+ 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, char *tname, int 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);
+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, 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 index, int size);
+
+
+#endif /* qhDEFset */
diff --git a/extern/qhull/include/qhull/stat.h b/extern/qhull/include/qhull/stat.h
new file mode 100755
index 00000000000..1dae54ed21d
--- /dev/null
+++ b/extern/qhull/include/qhull/stat.h
@@ -0,0 +1,520 @@
+ /*<html><pre> -<a href="qh-stat.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ stat.h
+ contains all statistics that are collected for qhull
+
+ see qh-stat.htm and stat.c
+
+ copyright (c) 1993-2002, The Geometry Center
+
+ 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
+
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="KEEPstatistics">-</a>
+
+ qh_KEEPstatistics
+ 0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="statistics">-</a>
+
+ 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">-</a>
+ remove leaders with query-replace-regexp [ ^I]+ (
+*/
+#if qh_KEEPstatistics
+enum statistics { /* alphabetical after Z/W */
+ Zacoplanar,
+ Wacoplanarmax,
+ Wacoplanartot,
+ Zangle,
+ Wangle,
+ Wanglemax,
+ Wanglemin,
+ Zangletests,
+ Wareatot,
+ Wareamax,
+ Wareamin,
+ Zavoidold,
+ Wavoidoldmax,
+ Wavoidoldtot,
+ Zback0,
+ Zbestcentrum,
+ Zbestdist,
+ 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,
+ Zvisvertextot,
+ Zvisvertexmax,
+ Zwidefacet,
+ Zwidevertices,
+ ZEND};
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="ZZstat">-</a>
+
+ 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 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,
+ Ztotmerge,
+ ZEND};
+#endif
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="ztype">-</a>
+
+ 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 =============*/
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="MAYdebugx">-</a>
+
+ MAYdebugx
+ define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zdef_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zinc_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zadd_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zval_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zmax_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zmin_">-</a>
+
+ 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 ==============*/
+
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="intrealT">-</a>
+
+ intrealT
+ union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT; /* union of int and realT */
+union intrealT {
+ int i;
+ realT r;
+};
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="qhstat">-</a>
+
+ qhstat
+ global data structure for statistics
+
+ 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 qhull.h
+
+ allocated in stat.c
+*/
+typedef struct qhstatT qhstatT;
+#if qh_QHpointer
+#define qhstat qh_qhstat->
+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 */
+ 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 index, int *nextindex);
+boolT qh_nostatistic (int i);
+void qh_printallstatistics (FILE *fp, char *string);
+void qh_printstatistics (FILE *fp, char *string);
+void qh_printstatlevel (FILE *fp, int id, int start);
+void qh_printstats (FILE *fp, int index, int *nextindex);
+realT qh_stddev (int num, realT tot, realT tot2, realT *ave);
+
+#endif /* qhDEFstat */
diff --git a/extern/qhull/include/qhull/user.h b/extern/qhull/include/qhull/user.h
new file mode 100755
index 00000000000..79558967a52
--- /dev/null
+++ b/extern/qhull/include/qhull/user.h
@@ -0,0 +1,762 @@
+/*<html><pre> -<a href="qh-user.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ user.h
+ user redefinable constants
+
+ see qh-user.htm. see COPYING for copyright information.
+
+ before reading any code, review qhull.h for data structure definitions and
+ the "qh" macro.
+*/
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/*============= data types and configuration macros ==========*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="realT">-</a>
+
+ realT
+ set the size of floating point numbers
+
+ qh_REALdigits
+ maximimum number of significant digits
+
+ qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+ format strings for printf
+
+ qh_REALmax, qh_REALmin
+ maximum and minimum (near zero) values
+
+ qh_REALepsilon
+ machine roundoff. Maximum roundoff error for addition and multiplication.
+
+ notes:
+ Select whether to store floating point numbers in single precision (float)
+ or double precision (double).
+
+ Use 'float' to save about 8% in time and 25% in space. This is particularly
+ help if high-d where convex hulls are space limited. Using 'float' also
+ reduces the printed size of Qhull's output since numbers have 8 digits of
+ precision.
+
+ Use 'double' when greater arithmetic precision is needed. This is needed
+ for Delaunay triangulations and Voronoi diagrams when you are not merging
+ facets.
+
+ If 'double' gives insufficient precision, your data probably includes
+ degeneracies. If so you should use facet merging (done by default)
+ or exact arithmetic (see imprecision section of manual, qh-impre.htm).
+ You may also use option 'Po' to force output despite precision errors.
+
+ You may use 'long double', but many format statements need to be changed
+ and you may need a 'long double' square root routine. S. Grundmann
+ (sg@eeiwzb.et.tu-dresden.de) has done this. He reports that the code runs
+ much slower with little gain in precision.
+
+ WARNING: on some machines, int f(){realT a= REALmax;return (a == REALmax);}
+ returns False. Use (a > REALmax/2) instead of (a == REALmax).
+
+ REALfloat = 1 all numbers are 'float' type
+ = 0 all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8 /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16 /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="CPUclock">-</a>
+
+ qh_CPUclock
+ define the clock() function for reporting the total time spent by Qhull
+ returns CPU ticks as a 'long int'
+ qh_CPUclock is only used for reporting the total time spent by Qhull
+
+ qh_SECticks
+ the number of clock ticks per second
+
+ notes:
+ looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+ to define a custom clock, set qh_CLOCKtype to 0
+
+ if your system does not use clock() to return CPU ticks, replace
+ qh_CPUclock with the corresponding function. It is converted
+ to unsigned long to prevent wrap-around during long runs.
+
+
+ Set qh_CLOCKtype to
+
+ 1 for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+ Note: may fail if more than 1 hour elapsed time
+
+ 2 use qh_clock() with POSIX times() (see global.c)
+*/
+#define qh_CLOCKtype 1 /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined (CLOCKS_PER_SECOND)
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined (CLOCKS_PER_SEC)
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined (CLK_TCK)
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock qh_clock() /* return CPU clock */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="RANDOM">-</a>
+
+ qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+ define random number generator
+
+ qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.
+ qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+ Set qh_RANDOMtype (default 5) to:
+ 1 for random() with 31 bits (UCB)
+ 2 for rand() with RAND_MAX or 15 bits (system 5)
+ 3 for rand() with 31 bits (Sun)
+ 4 for lrand48() with 31 bits (Solaris)
+ 5 for qh_rand() with 31 bits (included with Qhull)
+
+ notes:
+ Random numbers are used by rbox to generate point sets. Random
+ numbers are used by Qhull to rotate the input ('QRn' option),
+ simulate a randomized algorithm ('Qr' option), and to simulate
+ roundoff errors ('Rn' option).
+
+ Random number generators differ between systems. Most systems provide
+ rand() but the period varies. The period of rand() is not critical
+ since qhull does not normally use random numbers.
+
+ The default generator is Park & Miller's minimal standard random
+ number generator [CACM 31:1195 '88]. It is included with Qhull.
+
+ If qh_RANDOMmax is wrong, qhull will report a warning and Geomview
+ output will likely be invisible.
+*/
+#define qh_RANDOMtype 5 /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767) /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, Sun */
+#define qh_RANDOMint rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)
+#define qh_RANDOMmax ((realT)2147483646UL) /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand()
+#define qh_RANDOMseed_(seed) qh_srand(seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="ORIENTclock">-</a>
+
+ qh_ORIENTclock
+ 0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0
+
+
+/*========= performance related constants =========*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="HASHfactor">-</a>
+
+ qh_HASHfactor
+ total hash slots / used hash slots. Must be at least 1.1.
+
+ notes:
+ =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="VERIFYdirect">-</a>
+
+ qh_VERIFYdirect
+ with 'Tv' verify all points against all facets if op count is smaller
+
+ notes:
+ if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="INITIALsearch">-</a>
+
+ qh_INITIALsearch
+ if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="INITIALmax">-</a>
+
+ qh_INITIALmax
+ if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+
+ notes:
+ from points with non-zero determinants
+ use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEdefault">-</a>
+
+ qh_JOGGLEdefault
+ default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+ notes:
+ rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+ rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+ rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+ rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+ rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+ rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+ rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+ rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+ rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+ the later have about 20 points per facet, each of which may interfere
+
+ pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEincrease">-</a>
+
+ qh_JOGGLEincrease
+ factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEretry">-</a>
+
+ qh_JOGGLEretry
+ if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+ notes:
+ try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEagain">-</a>
+
+ qh_JOGGLEagain
+ every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+ notes:
+ 1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEmaxincrease">-</a>
+
+ qh_JOGGLEmaxincrease
+ maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+ relative to qh.MAXwidth
+
+ notes:
+ qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEmaxretry">-</a>
+
+ qh_JOGGLEmaxretry
+ stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 100
+
+/*========= memory constants =========*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MEMalign">-</a>
+
+ qh_MEMalign
+ memory alignment for qh_meminitbuffers() in global.c
+
+ notes:
+ 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 using gcc, best alignment is
+ #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign fmax_(sizeof(realT), sizeof(void *))
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MEMbufsize">-</a>
+
+ qh_MEMbufsize
+ size of additional memory buffers
+
+ notes:
+ used for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMbufsize 0x10000 /* allocate 64K memory buffers */
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MEMinitbuf">-</a>
+
+ qh_MEMinitbuf
+ size of initial memory buffer
+
+ notes:
+ use for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMinitbuf 0x20000 /* initially allocate 128K buffer */
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="INFINITE">-</a>
+
+ qh_INFINITE
+ on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE -10.101
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DEFAULTbox">-</a>
+
+ qh_DEFAULTbox
+ default box size (Geomview expects 0.5)
+*/
+#define qh_DEFAULTbox 0.5
+
+/*======= conditional compilation ============================*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="compiler">-</a>
+
+ __cplusplus
+ defined by C++ compilers
+
+ __MSC_VER
+ defined by Microsoft Visual C++
+
+ __MWERKS__ && __POWERPC__
+ defined by Metrowerks when compiling for the Power Macintosh
+
+ __STDC__
+ defined for strict ANSI C
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="COMPUTEfurthest">-</a>
+
+ qh_COMPUTEfurthest
+ compute furthest distance to an outside point instead of storing it with the facet
+ =1 to compute furthest
+
+ notes:
+ computing furthest saves memory but costs time
+ about 40% more distance tests for partitioning
+ removes facet->furthestdist
+*/
+#define qh_COMPUTEfurthest 0
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="KEEPstatistics">-</a>
+
+ qh_KEEPstatistics
+ =0 removes most of statistic gathering and reporting
+
+ notes:
+ if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 1
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXoutside">-</a>
+
+ qh_MAXoutside
+ record outer plane for each facet
+ =1 to record facet->maxoutside
+
+ notes:
+ this takes a realT per facet and slightly slows down qhull
+ it produces better outer planes for geomview output
+*/
+#define qh_MAXoutside 1
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="NOmerge">-</a>
+
+ qh_NOmerge
+ disables facet merging if defined
+
+ notes:
+ This saves about 10% space.
+
+ Unless 'Q0'
+ qh_NOmerge sets 'QJ' to avoid precision errors
+
+ #define qh_NOmerge
+
+ see:
+ <a href="mem.h#NOmem">qh_NOmem</a> in mem.c
+
+ see user.c/user_eg.c for removing io.o
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="NOtrace">-</a>
+
+ qh_NOtrace
+ no tracing if defined
+
+ notes:
+ This saves about 5% space.
+
+ #define qh_NOtrace
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="QHpointer">-</a>
+
+ qh_QHpointer
+ access global data with pointer or static structure
+
+ qh_QHpointer = 1 access globals via a pointer to allocated memory
+ enables qh_saveqhull() and qh_restoreqhull()
+ costs about 8% in time and 2% in space
+
+ = 0 qh_qh and qh_qhstat are static data structures
+ only one instance of qhull() can be active at a time
+ default value
+
+ notes:
+ all global variables for qhull are in qh, qhmem, and qhstat
+ qh is defined in qhull.h
+ qhmem is defined in mem.h
+ qhstat is defined in stat.h
+
+ see:
+ user_eg.c for an example
+*/
+#define qh_QHpointer 0
+#if 0 /* sample code */
+ qhT *oldqhA, *oldqhB;
+
+ exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ /* use results from first call to qh_new_qhull */
+ oldqhA= qh_save_qhull();
+ exitcode= qh_new_qhull (dimB, numpointsB, pointsB, ismalloc,
+ flags, outfile, errfile);
+ /* use results from second call to qh_new_qhull */
+ oldqhB= qh_save_qhull();
+ qh_restore_qhull (&oldqhA);
+ /* use results from first call to qh_new_qhull */
+ qh_freeqhull (qh_ALL); /* frees all memory used by first call */
+ qh_restore_qhull (&oldqhB);
+ /* use results from second call to qh_new_qhull */
+ qh_freeqhull (!qh_ALL); /* frees long memory used by second call */
+ qh_memfreeshort (&curlong, &totlong); /* frees short memory and memory allocator */
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="QUICKhelp">-</a>
+
+ qh_QUICKhelp
+ =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp 0
+
+/* ============ -merge constants- ====================
+
+ These constants effect facet merging. You probably will not need
+ to modify these. They effect the performance of facet merging.
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DIMmergeVertex">-</a>
+
+ qh_DIMmergeVertex
+ max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DIMreduceBuild">-</a>
+
+ qh_DIMreduceBuild
+ max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="BESTcentrum">-</a>
+
+ qh_BESTcentrum
+ if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+ else, qh_findbestneighbor() tests all vertices (much better merges)
+
+ qh_BESTcentrum2
+ if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="BESTnonconvex">-</a>
+
+ qh_BESTnonconvex
+ if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+
+ notes:
+ It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXnewmerges">-</a>
+
+ qh_MAXnewmerges
+ if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+
+ notes:
+ It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXnewcentrum">-</a>
+
+ qh_MAXnewcentrum
+ if <= dim+n vertices (n approximates the number of merges),
+ reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+
+ notes:
+ needed to reduce cost and because centrums may move too much if
+ many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="COPLANARratio">-</a>
+
+ qh_COPLANARratio
+ for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+ notes:
+ for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DISToutside">-</a>
+
+ qh_DISToutside
+ When is a point clearly outside of a facet?
+ Stops search in qh_findbestnew or qh_partitionall
+ qh_findbest uses qh.MINoutside since since it is only called if no merges.
+
+ notes:
+ 'Qf' always searches for best facet
+ if !qh.MERGING, same as qh.MINoutside.
+ if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+ [Note: Zdelvertextot occurs normally with interior points]
+ RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+ When there is a sharp edge, need to move points to a
+ clearly good facet; otherwise may be lost in another partitioning.
+ if too big then O(n^2) behavior for partitioning in cone
+ if very small then important points not processed
+ Needed in qh_partitionall for
+ RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+ Needed in qh_findbestnew for many instances of
+ RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+ See:
+ qh_DISToutside -- when is a point clearly outside of a facet
+ qh_SEARCHdist -- when is facet coplanar with the best facet?
+ qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+ fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="RATIOnearinside">-</a>
+
+ qh_RATIOnearinside
+ ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+ qh_check_maxout().
+
+ notes:
+ This is overkill since do not know the correct value.
+ It effects whether 'Qc' reports all coplanar points
+ Not used for 'd' since non-extreme points are coplanar
+*/
+#define qh_RATIOnearinside 5
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="SEARCHdist">-</a>
+
+ qh_SEARCHdist
+ When is a facet coplanar with the best facet?
+ qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+
+ See:
+ qh_DISToutside -- when is a point clearly outside of a facet
+ qh_SEARCHdist -- when is facet coplanar with the best facet?
+ qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+ (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="USEfindbestnew">-</a>
+
+ qh_USEfindbestnew
+ Always use qh_findbestnew for qh_partitionpoint, otherwise use
+ qh_findbestnew if merged new facet or sharpnewfacets.
+
+ See:
+ qh_DISToutside -- when is a point clearly outside of a facet
+ qh_SEARCHdist -- when is facet coplanar with the best facet?
+ qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="WIDEcoplanar">-</a>
+
+ qh_WIDEcoplanar
+ n*MAXcoplanar or n*MINvisible for a WIDEfacet
+
+ if vertex is further than qh.WIDEfacet from the hyperplane
+ then its ridges are not counted in computing the area, and
+ the facet's centrum is frozen.
+
+ notes:
+ qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+ qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXnarrow">-</a>
+
+ qh_MAXnarrow
+ max. cosine in initial hull that sets qh.NARROWhull
+
+ notes:
+ If qh.NARROWhull, the initial partition does not make
+ coplanar points. If narrow, a coplanar point can be
+ coplanar to two facets of opposite orientations and
+ distant from the exact convex hull.
+
+ Conservative estimate. Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="WARNnarrow">-</a>
+
+ qh_WARNnarrow
+ max. cosine in initial hull to warn about qh.NARROWhull
+
+ notes:
+ this is a conservative estimate.
+ Don't actually see problems until it is -1.0. See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="ZEROdelaunay">-</a>
+
+ qh_ZEROdelaunay
+ a zero Delaunay facet occurs for input sites coplanar with their convex hull
+ the last normal coefficient of a zero Delaunay facet is within
+ qh_ZEROdelaunay * qh.ANGLEround of 0
+
+ notes:
+ qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+ You can avoid zero Delaunay facets by surrounding the input with a box.
+
+ Use option 'PDk:-n' to explicitly define zero Delaunay facets
+ k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+ n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+#endif /* qh_DEFuser */
+
+
+
diff --git a/extern/qhull/src/Make-config.sh b/extern/qhull/src/Make-config.sh
new file mode 100755
index 00000000000..90bbb958599
--- /dev/null
+++ b/extern/qhull/src/Make-config.sh
@@ -0,0 +1,285 @@
+#!/bin/sh -e
+#
+# Make-config.sh
+#
+# Setup for Debian build
+#
+# Writes configure.in and Makefile.am files
+# and runs automake and autoconfig
+#
+# Use 'make dist' to build Unix distribution.
+# Use 'configure; make' to build Qhull
+#
+#note:
+# 'configure; make' does not work under cygwin.
+# src/unix.c:354: variable 'qh_qh' can't be auto-imported.
+# Please read the documentation for ld's --enable-auto-import for details.
+
+###################################################
+########### ../configure.in ######################
+###################################################
+
+echo Create ../configure.in
+cat >../configure.in <<\HERE-CONFIGURE
+dnl configure.in for the qhull package
+dnl Author: Rafael Laboissiere <rafael@debian.org>
+dnl Created: Mon Dec 3 21:36:21 CET 2001
+
+AC_INIT(src/qhull.c)
+AM_INIT_AUTOMAKE(qhull, 2002.1)
+
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_OUTPUT([Makefile src/Makefile html/Makefile eg/Makefile])
+
+HERE-CONFIGURE
+
+###################################################
+########### ../Makefile.am #######################
+###################################################
+
+echo Create ../Makefile.am
+cat >../Makefile.am <<\HERE-TOP
+### Makefile.am for the qhull package (main)
+### Author: Rafael Laboissiere <rafael@debian.org>
+### Created: Mon Dec 3 21:36:21 CET 2001
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+
+# which:
+doc_DATA = \
+ Announce.txt \
+ COPYING.txt \
+ README.txt \
+ REGISTER.txt
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+ $(doc_DATA) \
+ File_id.diz \
+ QHULL-GO.pif
+
+### Subdirectories for Automaking
+
+SUBDIRS = src html eg
+
+HERE-TOP
+
+###################################################
+########### ../eg/Makefile.am ####################
+###################################################
+
+echo Create ../eg/Makefile.am
+cat >../eg/Makefile.am <<\HERE-AM
+### Makefile.am for the qhull package (eg)
+### Author: Rafael Laboissiere <rafael@debian.org>
+### Created: Mon Dec 3 21:36:21 CET 2001
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+examplesdir = $(docdir)/examples
+
+# which:
+examples_DATA = \
+ q_eg \
+ q_egtest \
+ q_test \
+ Qhull-go.bat \
+ q_test.bat
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = $(examples_DATA)
+
+HERE-AM
+
+###################################################
+########### ../html/Makefile.am ##################
+###################################################
+
+echo Create ../html/Makefile.am
+cat >../html/Makefile.am <<\HERE-HTML
+### Makefile.am for the qhull package (html)
+### Author: Rafael Laboissiere <rafael@debian.org>
+### Created: Mon Dec 3 21:36:21 CET 2001
+
+### Man pages (trick to get around .man extension)
+
+%.1: %.man
+ cp $< $@
+CLEANFILES = *.1
+man_MANS = rbox.1 qhull.1
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+htmldir = $(docdir)/html
+
+# which:
+html_DATA = \
+ index.htm \
+ qconvex.htm \
+ qdelau_f.htm \
+ qdelaun.htm \
+ qh--4d.gif \
+ qh--cone.gif \
+ qh--dt.gif \
+ qh--geom.gif \
+ qh--half.gif \
+ qh--rand.gif \
+ qh-eg.htm \
+ qh-faq.htm \
+ qh-get.htm \
+ qh-home.htm \
+ qh-impre.htm \
+ qh-in.htm \
+ qh-optc.htm \
+ qh-optf.htm \
+ qh-optg.htm \
+ qh-opto.htm \
+ qh-optp.htm \
+ qh-optq.htm \
+ qh-optt.htm \
+ qh-quick.htm \
+ qhalf.htm \
+ qhull.htm \
+ qvoron_f.htm \
+ qvoronoi.htm \
+ rbox.htm
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+ $(html_DATA) \
+ qhull.man \
+ qhull.txt \
+ rbox.man \
+ rbox.txt
+
+HERE-HTML
+
+###################################################
+########### ../src/Makefile.am ###################
+###################################################
+
+echo Create ../src/Makefile.am
+cat >../src/Makefile.am <<\HERE-SRC
+### Makefile.am for the qhull package (src)
+### Author: Rafael Laboissiere <rafael@debian.org>
+### Created: Mon Dec 3 21:36:21 CET 2001
+
+### Shared Library
+
+# to:
+lib_LTLIBRARIES = libqhull.la
+
+# from:
+libqhull_la_SOURCES = \
+ user.c \
+ global.c \
+ stat.c \
+ io.c \
+ geom2.c \
+ poly2.c \
+ merge.c \
+ qhull.c \
+ geom.c \
+ poly.c \
+ qset.c \
+ mem.c
+
+# how:
+libqhull_la_LDFLAGS = -version-info 0:0:0 -lm
+
+### Utility programs
+
+# to:
+bin_PROGRAMS = qhull rbox qconvex qdelaunay qvoronoi qhalf
+
+# from:
+qhull_SOURCES = unix.c
+rbox_SOURCES = rbox.c
+qconvex_SOURCES = qconvex.c
+qdelaunay_SOURCES = qdelaun.c
+qvoronoi_SOURCES = qvoronoi.c
+qhalf_SOURCES = qhalf.c
+
+# how:
+qhull_LDADD = libqhull.la
+rbox_LDADD = libqhull.la
+qconvex_LDADD = libqhull.la
+qdelaunay_LDADD = libqhull.la
+qvoronoi_LDADD = libqhull.la
+qhalf_LDADD = libqhull.la
+
+### Include files
+
+pkginclude_HEADERS = \
+ geom.h \
+ mem.h \
+ poly.h \
+ qhull_a.h \
+ stat.h \
+ io.h \
+ merge.h \
+ qhull.h \
+ qset.h \
+ user.h
+
+
+### Example programs
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+examplesdir = $(docdir)/examples
+
+# which:
+examples_DATA = \
+ user_eg.c \
+ user_eg2.c \
+ qhull_interface.cpp \
+ Makefile.txt \
+ Make-config.sh \
+ MBorland
+
+doc_DATA = Changes.txt \
+ index.htm \
+ qh-geom.htm \
+ qh-globa.htm \
+ qh-io.htm \
+ qh-mem.htm \
+ qh-merge.htm \
+ qh-poly.htm \
+ qh-qhull.htm \
+ qh-set.htm \
+ qh-stat.htm \
+ qh-user.htm
+
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+ $(doc_DATA) \
+ $(examples_DATA)
+
+HERE-SRC
+
+###################################################
+########### run automake autoconf ################
+###################################################
+
+
+echo Run automake, libtoolize, and autoconf
+cd ..; aclocal &&\
+ automake --foreign --add-missing --force-missing && \
+ libtoolize --force && \
+ autoconf
+
diff --git a/extern/qhull/src/Makefile.txt b/extern/qhull/src/Makefile.txt
new file mode 100755
index 00000000000..e87b66b49bc
--- /dev/null
+++ b/extern/qhull/src/Makefile.txt
@@ -0,0 +1,190 @@
+# Unix Makefile for qhull and rbox
+#
+# see README.txt
+#
+# make to produce qhull qconvex qdelaunay qhalf qvoronoi rbox
+# make qvoronoi to produce qvoronoi (etc.)
+# make qhullx to produce qhull qconvex etc. w/o using libqhull.a
+# make doc to print documentation
+# make install to copy qhull, rbox, qhull.1, rbox.1 to BINDIR, MANDIR
+# make new to rebuild qhull and rbox from source
+#
+# make printall to print all files
+# make user_eg to produce user_eg
+# make user_eg2 to produce user_eg2
+# make clean to remove object files and core
+# make cleanall to remove all generated files
+#
+# PRINTMAN -- command for printing manual pages
+# PRINTC -- command for printing C files
+# BINDIR -- directory where to copy executables
+# MANDIR -- directory where to copy manual pages
+# CC -- ANSI C or C++ compiler
+# CCOPTS1 - options used to compile .c files
+# CCOPTS2 -- options used to link .o files
+#
+# CFILES -- .c files for printing
+# HFILES -- .h files for printing
+# DFILES -- documentation files
+# MFILES -- man pages and html files
+# TFILES -- .txt versions of html html files
+# FILES -- all other files
+# OBJS -- specifies the object files of libqhull.a
+#
+BINDIR = /usr/local/bin
+MANDIR = /usr/local/man/man1
+
+# if you do not have enscript, try a2ps or just use lpr. The files are text.
+PRINTMAN = enscript -2rl
+PRINTC = enscript -2r
+# PRINTMAN = lpr
+# PRINTC = lpr
+
+#for Gnu's gcc compiler -O2 for optimization, -g for debugging, -Wall for check
+#
+CC = gcc
+CCOPTS1 = -O2 -ansi
+
+# for Sun's cc compiler, -fast or O2 for optimization, -g for debugging, -Xc for ANSI
+#CC = cc
+#CCOPTS1 = -Xc -v -fast
+
+# for Silicon Graphics cc compiler, -O2 for optimization, -g for debugging
+#CC = cc
+#CCOPTS1 = -ansi -O2
+
+# for Next cc compiler with fat executable
+#CC = cc
+#CCOPTS1 = -ansi -O2 -arch m68k -arch i386 -arch hppa
+
+# for loader, ld
+CCOPTS2 = $(CCOPTS1)
+
+# OBJS in execution frequency order. CFILES after qhull.c are alphabetical
+OBJS = user.o global.o stat.o io.o geom2.o poly2.o \
+ merge.o qhull.o geom.o poly.o qset.o mem.o
+
+CFILES= unix.c qhull.c geom.c geom2.c global.c io.c mem.c merge.c poly.c \
+ poly2.c qset.c stat.c user.c qconvex.c qdelaun.c qhalf.c qvoronoi.c
+HFILES= user.h qhull.h qhull_a.h geom.h io.h mem.h merge.h poly.h qset.h stat.h
+TXTFILES= ../Announce.txt ../REGISTER.txt ../COPYING.txt ../README.txt Changes.txt
+DOCFILES= ../html/rbox.txt ../html/qhull.txt
+FILES= Makefile rbox.c user_eg.c ../eg/q_test ../eg/q_egtest ../eg/q_eg
+HTMFILES= qhull.man rbox.man qh-in.htm qh-optg.htm qh-optt.htm qh-optp.htm \
+ index.htm qh-quick.htm qh-impre.htm qh-eg.htm \
+ qh-optc.htm qh-opto.htm qh-optf.htm qh-optq.htm \
+ qh-c.htm qh-faq.htm qhull.htm qconvex.htm qdelaun.htm \
+ qh-geom.htm qh-globa.htm qh-io.htm qh-mem.htm qh-merge.htm \
+ qh-poly.htm qh-qhull.htm qh-set.htm qh-stat.htm qh-user.htm \
+ qdelau_f.htm qhalf.htm qvoronoi.htm qvoron_f.htm rbox.htm
+
+all: rbox qconvex qdelaunay qhalf qvoronoi qhull
+
+unix.o: qhull.h user.h mem.h
+qconvex.o: qhull.h user.h mem.h
+qdelaun.o: qhull.h user.h mem.h
+qhalf.o: qhull.h user.h mem.h
+qvoronoi.o: qhull.h user.h mem.h
+qhull.o: $(HFILES)
+geom.o: $(HFILES)
+geom2.o: $(HFILES)
+global.o: $(HFILES)
+io.o: $(HFILES)
+mem.o: mem.h
+merge.o: $(HFILES)
+poly.o: $(HFILES)
+poly2.o: $(HFILES)
+qset.o: qset.h mem.h
+stat.o: $(HFILES)
+user.o: $(HFILES)
+
+.c.o:
+ $(CC) -c $(CCOPTS1) $<
+
+clean:
+ rm -f *.o ../core qconvex qdelaunay qhalf qvoronoi qhull libqhull.a \
+ *.exe
+
+cleanall: clean
+ rm -f *~ ../rbox ../qhull ../qhalf ../qconvex ../qdelaunay ../qhalf\
+ ../qvoronoi ../user_eg ../user_eg2 ../*.exe >/dev/null
+
+doc:
+ $(PRINTMAN) $(TXTFILES) $(DOCFILES)
+
+install: all
+ cp ../qconvex $(BINDIR)/qconvex
+ cp ../qdelaunay $(BINDIR)/qdelaunay
+ cp ../qhalf $(BINDIR)/qhalf
+ cp ../qhull $(BINDIR)/qhull
+ cp ../qvoronoi $(BINDIR)/qvoronoi
+ cp ../rbox $(BINDIR)/rbox
+ cp ../html/qhull.man $(MANDIR)/qhull.1
+ cp ../html/rbox.man $(MANDIR)/rbox.1
+
+new: cleanall all
+
+printall: doc printh printc printf
+
+printh:
+ $(PRINTC) $(HFILES)
+
+printc:
+ $(PRINTC) $(CFILES)
+
+printf:
+ $(PRINTC) $(FILES)
+
+libqhull.a: $(OBJS)
+ @echo if 'ar' or 'ranlib' fails, try 'make qhullx'
+ ar r libqhull.a $(OBJS)
+ @echo the next line may need to be removed.
+ -test -x /bin/ranlib -o -x /usr/bin/ranlib && ranlib libqhull.a
+
+# don't use ../qconvex. Does not work on Red Hat Linux
+qconvex: qconvex.o libqhull.a
+ $(CC) -o qconvex $(CCOPTS2) qconvex.o -L. -lqhull -lm
+ cp qconvex ..
+
+qdelaunay: qdelaun.o libqhull.a
+ $(CC) -o qdelaunay $(CCOPTS2) qdelaun.o -L. -lqhull -lm
+ cp qdelaunay ..
+
+qhalf: qhalf.o libqhull.a
+ $(CC) -o qhalf $(CCOPTS2) qhalf.o -L. -lqhull -lm
+ cp qhalf ..
+
+qvoronoi: qvoronoi.o libqhull.a
+ $(CC) -o qvoronoi $(CCOPTS2) qvoronoi.o -L. -lqhull -lm
+ cp qvoronoi ..
+
+qhull: unix.o libqhull.a
+ $(CC) -o qhull $(CCOPTS2) unix.o -L. -lqhull -lm
+ cp qhull ..
+ -chmod +x ../eg/q_test ../eg/q_eg ../eg/q_egtest
+ -cd ..; ./rbox D4 | ./qhull
+
+# compile qhull without using libqhull.a
+qhullx: qconvex.o qdelaun.o qhalf.o qvoronoi.o unix.o $(OBJS)
+ $(CC) -o qconvex $(CCOPTS2) qconvex.o $(OBJS) -lm
+ $(CC) -o qdelaunay $(CCOPTS2) qdelaun.o $(OBJS) -lm
+ $(CC) -o qhalf $(CCOPTS2) qhalf.o $(OBJS) -lm
+ $(CC) -o qvoronoi $(CCOPTS2) qvoronoi.o $(OBJS) -lm
+ $(CC) -o qhull $(CCOPTS2) unix.o $(OBJS) -lm
+ cp qconvex qdelaunay qhalf qvoronoi qhull ..
+ -chmod +x ../eg/q_test ../eg/q_eg ../eg/q_egtest
+ -cd ..; ./rbox D4 | ./qhull
+
+rbox: rbox.o
+ $(CC) -o rbox rbox.o $(CCOPTS2) -lm
+ cp rbox ..
+
+user_eg: user_eg.o libqhull.a
+ $(CC) -o user_eg $(CCOPTS2) user_eg.o -L. -lqhull -lm
+ cp user_eg ..
+
+user_eg2: user_eg2.o libqhull.a
+ $(CC) -o user_eg2 $(CCOPTS2) user_eg2.o -L. -lqhull -lm
+ cp user_eg2 ..
+
+# end of Makefile
diff --git a/extern/qhull/src/geom.c b/extern/qhull/src/geom.c
new file mode 100755
index 00000000000..b3cf198d510
--- /dev/null
+++ b/extern/qhull/src/geom.c
@@ -0,0 +1,1230 @@
+/*<html><pre> -<a href="qh-geom.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ geom.c
+ geometric routines of qhull
+
+ see qh-geom.htm and geom.h
+
+ copyright (c) 1993-2002 The Geometry Center
+
+ infrequent code goes into geom2.c
+*/
+
+#include "qhull_a.h"
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="distplane">-</a>
+
+ 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 sortfacets)
+
+ see:
+ qh_distnorm in geom2.c
+*/
+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) {
+ fprintf (qh ferr, "qh_distplane: ");
+ fprintf (qh ferr, qh_REAL_1, *dist);
+ fprintf (qh ferr, "from p%d to f%d\n", qh_pointid(point), facet->id);
+ }
+ return;
+} /* distplane */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="findbest">-</a>
+
+ 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, *bestfacet= NULL;
+ facetT *bestfacet_all= startfacet;
+ 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;
+ fprintf (qh ferr, "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);
+ fprintf(qh ferr, " testhorizon? %d noupper? %d", testhorizon, noupper);
+ fprintf (qh ferr, " Last point added was p%d.", qh furthest_id);
+ fprintf(qh ferr, " 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, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
+ facet->id, bestdist, getid_(bestfacet)));
+ 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 neighor */
+ } /* 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) {
+ fprintf(qh ferr, "\n\
+qh_findbest: all neighbors of facet %d are flipped or upper Delaunay.\n\
+Please report this error to qhull_bug@geom.umn.edu with the input and all of the output.\n",
+ startfacet->id);
+ qh_errexit (qh_ERRqhull, startfacet, NULL);
+ }
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="findbesthorizon">-</a>
+
+ 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 coplanarset */
+ int numpartinit= *numpart, coplanarset_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);
+ }
+ coplanarset_size= 0;
+ facet= startfacet;
+ while (True) {
+ trace4((qh ferr, "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.coplanarset at least searchdist below */
+ coplanarset_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 (!coplanarset_size++) {
+ SETfirst_(qh coplanarset)= nextfacet;
+ SETtruncate_(qh coplanarset, 1);
+ }else
+ qh_setappend (&qh coplanarset, 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 (!coplanarset_size)
+ break;
+ else if (!--coplanarset_size) {
+ facet= SETfirst_(qh coplanarset);
+ SETtruncate_(qh coplanarset, 0);
+ }else
+ facet= (facetT*)qh_setdellast (qh coplanarset);
+ } /* while True, for each facet in qh.coplanarset */
+ if (!ischeckmax) {
+ zadd_(Zfindhorizontot, *numpart - numpartinit);
+ zmax_(Zfindhorizonmax, *numpart - numpartinit);
+ if (newbest)
+ zinc_(Zparthorizon);
+ }
+ trace4((qh ferr, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));
+ return bestfacet;
+} /* findbesthorizon */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="findbestnew">-</a>
+
+ 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.coplanarset.
+ If share visit_id with qh_findbest, coplanarset 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, minsearch= -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)
+ fprintf(qh ferr, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets. Can not continue.\n");
+ else
+ fprintf(qh ferr, "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;
+ fprintf(qh ferr, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",
+ qh_pointid(point), startfacet->id, isdistoutside, distoutside);
+ fprintf(qh ferr, " Last point added p%d visitid %d.", qh furthest_id, visitid);
+ fprintf(qh ferr, " 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, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));
+ qh IStracing= oldtrace;
+ return bestfacet;
+} /* findbestnew */
+
+/* ============ hyperplane functions -- keep code together [?] ============ */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="backnormal">-</a>
+
+ 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, "qh_backnormal: zero diagonal at column %d.\n", i));
+ qh_precision ("zero diagonal on back substitution");
+ }
+} /* backnormal */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="gausselim">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="getangle">-</a>
+
+ 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, "qh_getangle: %2.2g\n", angle));
+ return(angle);
+} /* getangle */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="getcenter">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="getcentrum">-</a>
+
+ 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, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
+ facet->id, qh_setsize(facet->vertices), dist));
+ return centrum;
+} /* getcentrum */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="getdistance">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="normalize">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="normalize2">-</a>
+
+ 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, "qh_normalize: norm=%2.2g too small during p%d\n",
+ norm, qh furthest_id));
+ return;
+ }
+ }
+ }
+} /* normalize */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="projectpoint">-</a>
+
+ 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,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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="setfacetplane">-</a>
+
+ 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 k,i, normsize= qh normal_size, 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;
+ fprintf (qh ferr, "qh_setfacetplane: facet f%d created.\n", facet->id);
+ fprintf (qh ferr, " Last point added to hull was p%d.", qh furthest_id);
+ if (zzval_(Ztotmerge))
+ fprintf(qh ferr, " Last merge was #%d.", zzval_(Ztotmerge));
+ fprintf (qh ferr, "\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();
+ }
+ }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_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, "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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "qh_setfacetplane: f%d offset %2.2g normal: ",
+ facet->id, facet->offset);
+ for (k=0; k < qh hull_dim; k++)
+ fprintf (qh ferr, "%2.2g ", facet->normal[k]);
+ fprintf (qh ferr, "\n");
+ }
+ if (facet == qh tracefacet)
+ qh IStracing= oldtrace;
+} /* setfacetplane */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="sethyperplane_det">-</a>
+
+ 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, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh furthest_id));
+ zzinc_(Znearlysingular);
+ }
+} /* sethyperplane_det */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="sethyperplane_gauss">-</a>
+
+ 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, "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, "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/extern/qhull/src/geom.h b/extern/qhull/src/geom.h
new file mode 100755
index 00000000000..32440cff56f
--- /dev/null
+++ b/extern/qhull/src/geom.h
@@ -0,0 +1,177 @@
+/*<html><pre> -<a href="qh-geom.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ geom.h
+ header file for geometric routines
+
+ see qh-geom.htm and geom.c
+
+ copyright (c) 1993-2002 The Geometry Center
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+/* ============ -macros- ======================== */
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="fabs_">-</a>
+
+ fabs_(a)
+ returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="fmax_">-</a>
+
+ fmax_(a,b)
+ returns the maximum value of a and b
+*/
+#define fmax_( a,b ) ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="fmin_">-</a>
+
+ fmin_(a,b)
+ returns the minimum value of a and b
+*/
+#define fmin_( a,b ) ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="maximize_">-</a>
+
+ maximize_(maxval, val)
+ set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) {if (( maxval ) < ( val )) ( maxval )= ( val );}
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="minimize_">-</a>
+
+ minimize_(minval, val)
+ set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) {if (( minval ) > ( val )) ( minval )= ( val );}
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="det2_">-</a>
+
+ det2_(a1, a2,
+ b1, b2)
+
+ compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="det3_">-</a>
+
+ 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 ) )
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="dX">-</a>
+
+ 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, char *string, realT **rows, int numrow, int numcol);
+void qh_printpoints (FILE *fp, 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);
+int qh_rand( void);
+void qh_srand( int seed);
+realT qh_randomfactor (void);
+void qh_randommatrix (realT *buffer, int dim, realT **row);
+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/extern/qhull/src/geom2.c b/extern/qhull/src/geom2.c
new file mode 100755
index 00000000000..bd58ce1282b
--- /dev/null
+++ b/extern/qhull/src/geom2.c
@@ -0,0 +1,2160 @@
+/*<html><pre> -<a href="qh-geom.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+
+ geom2.c
+ infrequently used geometric routines of qhull
+
+ see qh-geom.htm and geom.h
+
+ copyright (c) 1993-2002 The Geometry Center
+
+ frequently used code goes into geom.c
+*/
+
+#include "qhull_a.h"
+
+/*================== functions in alphabetic order ============*/
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="copypoints">-</a>
+
+ qh_copypoints( points, numpoints, dimension)
+ return malloc'd copy of points
+*/
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension) {
+ int size;
+ coordT *newpoints;
+
+ size= numpoints * dimension * sizeof(coordT);
+ if (!(newpoints=(coordT*)malloc(size))) {
+ fprintf(qh ferr, "qhull error: insufficient memory to copy %d points\n",
+ numpoints);
+ qh_errexit(qh_ERRmem, NULL, NULL);
+ }
+ memcpy ((char *)newpoints, (char *)points, size);
+ return newpoints;
+} /* copypoints */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="crossproduct">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="determinant">-</a>
+
+ 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]
+ (not 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) {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="detjoggle">-</a>
+
+ 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, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
+ return joggle;
+} /* detjoggle */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="detroundoff">-</a>
+
+ 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 (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 (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) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="detsimplex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
+ det, qh_pointid(apex), dim, *nearzero));
+ return det;
+} /* detsimplex */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="distnorm">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="distround">-</a>
+
+ 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 (dimension) * maxabs;
+ minimize_( maxdistsum, maxsumabs);
+ maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
+ /* adds maxabs for offset */
+ trace4((qh ferr, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",
+ maxround, maxabs, maxsumabs, maxdistsum));
+ return maxround;
+} /* distround */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="divzero">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="facetarea">-</a>
+
+ 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, (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, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
+ return area;
+} /* facetarea */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="facetarea_simplex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="facetcenter">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="findgooddist">-</a>
+
+ 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) {
+ zinc_(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;
+ zinc_(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, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
+ qh_pointid(point), bestdist, bestfacet->id));
+ return bestfacet;
+ }
+ trace4((qh ferr, "qh_findgooddist: no good facet for p%d above f%d\n",
+ qh_pointid(point), facetA->id));
+ return NULL;
+} /* findgooddist */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="getarea">-</a>
+
+ qh_getarea( facetlist )
+ set area of all facets in facetlist
+ collect statistics
+
+ 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 REPORTfreq)
+ fprintf (qh ferr, "computing area of each facet and volume of the convex hull\n");
+ else
+ trace1((qh ferr, "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;
+ facet->f.area= area= qh_facetarea (facet);
+ facet->isarea= True;
+ 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);
+ }
+ }
+} /* getarea */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="gram_schmidt">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="inthresholds">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="joggleinput">-</a>
+
+ 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 size, i, seed;
+ 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*)malloc(size))) {
+ fprintf(qh ferr, "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)) {
+ fprintf (qh ferr, "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, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="maxabsval">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="maxmin">-</a>
+
+ 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 {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="maxouter">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="maxsimplex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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 {
+ fprintf (qh ferr, "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, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
+ }else {
+ trace0((qh ferr, "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) {
+ fprintf (qh ferr, "qhull internal error (qh_maxsimplex): not enough points available\n");
+ qh_errexit (qh_ERRqhull, NULL, NULL);
+ }
+ qh_setappend(simplex, maxpoint);
+ trace1((qh ferr, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
+ qh_pointid(maxpoint), k+1, maxdet));
+ } /* k */
+} /* maxsimplex */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="minabsval">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="mindiff">-</a>
+
+ 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 */
+
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="orientoutside">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="outerinner">-</a>
+
+ 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
+
+ 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 (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 (qh hull_dim);
+ }
+} /* outerinner */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="pointdist">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="printmatrix">-</a>
+
+ 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, char *string, realT **rows, int numrow, int numcol) {
+ realT *rowp;
+ realT r; /*bug fix*/
+ int i,k;
+
+ fprintf (fp, "%s\n", string);
+ for (i= 0; i < numrow; i++) {
+ rowp= rows[i];
+ for (k= 0; k < numcol; k++) {
+ r= *rowp++;
+ fprintf (fp, "%6.3g ", r);
+ }
+ fprintf (fp, "\n");
+ }
+} /* printmatrix */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="printpoints">-</a>
+
+ 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, char *string, setT *points) {
+ pointT *point, **pointp;
+
+ if (string) {
+ fprintf (fp, "%s", string);
+ FOREACHpoint_(points)
+ fprintf (fp, " p%d", qh_pointid(point));
+ fprintf (fp, "\n");
+ }else {
+ FOREACHpoint_(points)
+ fprintf (fp, " %d", qh_pointid(point));
+ fprintf (fp, "\n");
+ }
+} /* printpoints */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="projectinput">-</a>
+
+ 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);
+ 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) {
+ fprintf(qh ferr, "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*)malloc(newnum*newdim*sizeof(coordT)))){
+ fprintf(qh ferr, "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, "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) {
+ fprintf(qh ferr, "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)
+ 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=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, "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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="projectpoints">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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<n; j++) {
+ if (project[j] == -1)
+ oldk++;
+ else {
+ newp= newpoints+newk++;
+ if (project[j] == +1) {
+ if (oldk >= 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, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
+ numpoints, dim, newdim));
+} /* projectpoints */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="rand">-</a>
+
+ qh_rand()
+ qh_srand( seed )
+ generate pseudo-random number between 1 and 2^31 -2
+
+ notes:
+ from Park & Miller's minimimal standard random number generator
+ Communications of the ACM, 31:1192-1201, 1988.
+ does not use 0 or 2^31 -1
+ this is silently enforced by qh_srand()
+ can make 'Rn' much faster by moving qh_rand to qh_distplane
+*/
+int qh_rand_seed= 1; /* define as global variable instead of using qh */
+
+int qh_rand( void) {
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773 /* m div a */
+#define qh_rand_r 2836 /* m mod a */
+ int lo, hi, test;
+ int seed = qh_rand_seed;
+
+ hi = seed / qh_rand_q; /* seed div q */
+ lo = seed % qh_rand_q; /* seed mod q */
+ test = qh_rand_a * lo - qh_rand_r * hi;
+ if (test > 0)
+ seed= test;
+ else
+ seed= test + qh_rand_m;
+ qh_rand_seed= seed;
+ /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */
+ /* seed = qh_RANDOMmax; for testing */
+ return seed;
+} /* rand */
+
+void qh_srand( int seed) {
+ if (seed < 1)
+ qh_rand_seed= 1;
+ else if (seed >= qh_rand_m)
+ qh_rand_seed= qh_rand_m - 1;
+ else
+ qh_rand_seed= seed;
+} /* qh_srand */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="randomfactor">-</a>
+
+ qh_randomfactor()
+ return a random factor within qh.RANDOMmax of 1.0
+
+ notes:
+ qh.RANDOMa/b are defined in global.c
+*/
+realT qh_randomfactor (void) {
+ realT randr;
+
+ randr= qh_RANDOMint;
+ return randr * qh RANDOMa + qh RANDOMb;
+} /* randomfactor */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="randommatrix">-</a>
+
+ qh_randommatrix( buffer, dim, rows )
+ generate a random dim X dim matrix in range [-1,1]
+ assumes buffer is [dim+1, dim]
+
+ returns:
+ sets buffer to random numbers
+ sets rows to rows of buffer
+ sets row[dim] as scratch row
+*/
+void qh_randommatrix (realT *buffer, int dim, realT **rows) {
+ int i, k;
+ realT **rowi, *coord, realr;
+
+ coord= buffer;
+ rowi= rows;
+ for (i=0; i < dim; i++) {
+ *(rowi++)= coord;
+ for (k=0; k < dim; k++) {
+ realr= qh_RANDOMint;
+ *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+ }
+ }
+ *rowi= coord;
+} /* randommatrix */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="rotateinput">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="rotatepoints">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="scaleinput">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="scalelast">-</a>
+
+ 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, "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)
+ fprintf (qh ferr, "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
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="scalepoints">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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, "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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="setdelaunay">-</a>
+
+ 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, "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 */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="sethalfspace">-</a>
+
+ 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) {
+ fprintf (qh ferr, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
+ for (k= dim, coordp= coords; k--; ) {
+ r= *coordp++;
+ fprintf (qh ferr, " %6.2g", r);
+ }
+ fprintf (qh ferr, "\n");
+ }
+ return True;
+LABELerroroutside:
+ feasiblep= feasible;
+ normp= normal;
+ fprintf(qh ferr, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
+ for (k= dim; k--; )
+ fprintf (qh ferr, qh_REAL_1, r=*(feasiblep++));
+ fprintf (qh ferr, "\n halfspace: ");
+ for (k= dim; k--; )
+ fprintf (qh ferr, qh_REAL_1, r=*(normp++));
+ fprintf (qh ferr, "\n at offset: ");
+ fprintf (qh ferr, qh_REAL_1, *offset);
+ fprintf (qh ferr, " and distance: ");
+ fprintf (qh ferr, qh_REAL_1, dist);
+ fprintf (qh ferr, "\n");
+ return False;
+} /* sethalfspace */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="sethalfspace_all">-</a>
+
+ 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, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
+ newdim= dim - 1;
+ if (!(newpoints=(coordT*)malloc(count*newdim*sizeof(coordT)))){
+ fprintf(qh ferr, "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)) {
+ fprintf (qh ferr, "The halfspace was at index %d\n", i);
+ qh_errexit (qh_ERRinput, NULL, NULL);
+ }
+ normalp= offsetp + 1;
+ }
+ return newpoints;
+} /* sethalfspace_all */
+
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="sharpnewfacets">-</a>
+
+ 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, "qh_sharpnewfacets: %d\n", issharp));
+ return issharp;
+} /* sharpnewfacets */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="voronoi_center">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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);
+ }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) {
+ fprintf (qh ferr, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
+ qh_printmatrix (qh ferr, "center:", &center, 1, dim);
+ if (qh IStracing >= 5) {
+ qh_printpoints (qh ferr, "points", simplex);
+ FOREACHpoint_(simplex)
+ fprintf (qh ferr, "p%d dist %.2g, ", qh_pointid (point),
+ qh_pointdist (point, center, dim));
+ fprintf (qh ferr, "\n");
+ }
+ }
+#endif
+ }
+ if (simplex != points)
+ qh_settempfree (&simplex);
+ return center;
+} /* voronoi_center */
+
diff --git a/extern/qhull/src/global.c b/extern/qhull/src/global.c
new file mode 100755
index 00000000000..d3e141aa985
--- /dev/null
+++ b/extern/qhull/src/global.c
@@ -0,0 +1,2018 @@
+/*<html><pre> -<a href="qh-globa.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ global.c
+ initializes all the globals of the qhull application
+
+ see README
+
+ see qhull.h for qh.globals and function prototypes
+
+ see qhull_a.h for internal functions
+
+ copyright (c) 1993-2002, The Geometry Center
+ */
+
+#include "qhull_a.h"
+
+/*========= qh definition =======================*/
+
+#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
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="appendprint">-</a>
+
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="checkflags">-</a>
+
+ 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, key, opt, prevopt;
+ char chkkey[]= " ";
+ char chkopt[]= " ";
+ char chkopt2[]= " ";
+
+ if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
+ fprintf(qh ferr, "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")) {
+ fprintf(qh ferr, "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 == '\'') { /* TO 'file name' */
+ t= strchr(s, '\'');
+ if (!t) {
+ fprintf(qh ferr, "qhull error (qh_checkflags): missing the 2nd single-quote for:\n%s\n", s-1);
+ qh_errexit(qh_ERRinput, NULL, NULL);
+ }
+ s= t+1;
+ 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]= '\'';
+ fprintf(qh ferr, "qhull error: option %s is not used with this program.\n It may be used with qhull.\n", chkerr);
+ qh_errexit(qh_ERRinput, NULL, NULL);
+ }
+ }
+} /* checkflags */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="clock">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="freebuffers">-</a>
+
+ qh_freebuffers()
+ free up global memory buffers
+
+ notes:
+ must match qh_initbuffers()
+*/
+void qh_freebuffers (void) {
+
+ trace5((qh ferr, "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 coplanarset);
+ if (qh line) /* allocated by qh_readinput, freed if no error */
+ free (qh line);
+ if (qh half_space)
+ free (qh half_space);
+ if (qh temp_malloc)
+ free (qh temp_malloc);
+ if (qh feasible_point) /* allocated by qh_readfeasible */
+ free (qh feasible_point);
+ if (qh feasible_string) /* allocated by qh_initflags */
+ 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) {
+ free(qh first_point);
+ qh first_point= NULL;
+ }
+ if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */
+ free (qh input_points);
+ qh input_points= NULL;
+ }
+ trace5((qh ferr, "qh_freebuffers: finished\n"));
+} /* freebuffers */
+
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="freebuild">-</a>
+
+ qh_freebuild( allmem )
+ free global memory used by qh_initbuild and qh_buildhull
+ if !allmem,
+ does not free short memory (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, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
+ if (qh del_vertices)
+ qh_settruncate (qh del_vertices, 0);
+ if (allmem) {
+ qh_clearcenters (qh_ASnone);
+ while ((vertex= qh vertex_list)) {
+ if (vertex->next)
+ qh_delvertex (vertex);
+ else {
+ qh_memfree (vertex, 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, 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, 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, sizeof(mergeT));
+ qh facet_mergeset= NULL; /* temp set */
+ qh degen_mergeset= NULL; /* temp set */
+ qh_settempfree_all();
+} /* freebuild */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="freeqhull">-</a>
+
+ qh_freeqhull( allmem )
+ free global memory
+ if !allmem,
+ does not free short memory (freed by qh_memfreeshort)
+
+ notes:
+ sets qh.NOerrexit in case caller forgets to
+
+ design:
+ free global and temporary memory from qh_initbuild and qh_buildhull
+ free buffers
+ free statistics
+*/
+void qh_freeqhull (boolT allmem) {
+
+ trace1((qh ferr, "qh_freeqhull: free global memory\n"));
+ qh NOerrexit= True; /* no more setjmp since called at exit */
+ qh_freebuild (allmem);
+ qh_freebuffers();
+ qh_freestatistics();
+#if qh_QHpointer
+ free (qh_qh);
+ qh_qh= NULL;
+#else
+ memset((char *)&qh_qh, 0, sizeof(qhT));
+ qh NOerrexit= True;
+#endif
+} /* freeqhull */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="init_A">-</a>
+
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="init_B">-</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 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="init_qhull_command">-</a>
+
+ qh_init_qhull_command( argc, argv )
+ build qh.qhull_command from argc/argv
+
+ returns:
+ a space-deliminated 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[]) {
+ int i;
+ char *s;
+
+ if (argc) {
+ if ((s= strrchr( argv[0], '\\'))) /* Borland gives full path */
+ strcpy (qh qhull_command, s+1);
+ else
+ strcpy (qh qhull_command, argv[0]);
+ if ((s= strstr (qh qhull_command, ".EXE"))
+ || (s= strstr (qh qhull_command, ".exe")))
+ *s= '\0';
+ }
+ for (i=1; i < argc; i++) {
+ if (strlen (qh qhull_command) + strlen(argv[i]) + 1 < sizeof(qh qhull_command)) {
+ strcat (qh qhull_command, " ");
+ strcat (qh qhull_command, argv[i]);
+ }else {
+ fprintf (qh ferr, "qhull input error: more than %d characters in command line\n",
+ (int)sizeof(qh qhull_command));
+ exit (1); /* can not use qh_errexit */
+ }
+ }
+} /* init_qhull_command */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="initflags">-</a>
+
+ 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]) {
+ *qh qhull_command= '\0';
+ strncat( qh qhull_command, command, sizeof( qh qhull_command));
+ }
+ 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 != '-')
+ fprintf(qh ferr, "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 != '-')
+ fprintf(qh ferr, "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 == '-')
+ fprintf(qh ferr, "qhull warning: negative maximum roundoff given for option 'An'. Ignored.\n");
+ else if (!isdigit(*s))
+ fprintf(qh ferr, "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
+ fprintf (qh ferr, "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 (t-start+1, 1))) {
+ fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
+ qh_errexit(qh_ERRmem, NULL, NULL);
+ }
+ strncpy (qh feasible_string, start, 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))
+ fprintf(qh ferr, "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 != '-')
+ fprintf(qh ferr, "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 != '-')
+ fprintf(qh ferr, "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 == '-')
+ fprintf(qh ferr, "qhull warning: negative outside width for option 'Wn'. Ignored.\n");
+ else if (!isdigit(*s))
+ fprintf(qh ferr, "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 '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--;
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "qhull input error: missing dimension for option 'GDn'\n");
+ else {
+ if (qh DROPdim >= 0)
+ fprintf (qh ferr, "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--;
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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--;
+ fprintf (qh ferr, "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, "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))
+ fprintf (qh ferr, "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--;
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "qhull warning: good point already defined for option 'QGn'. Ignored\n");
+ else if (s == t)
+ fprintf (qh ferr, "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 != '-')
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "qhull warning: good vertex already defined for option 'QVn'. Ignored\n");
+ else if (s == t)
+ fprintf (qh ferr, "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--;
+ fprintf (qh ferr, "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 '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 fout)
+ fprintf (qh ferr, "qhull warning: output file undefined (stdout). Option 'Tz' ignored.\n");
+ else {
+ qh_option ("Tz-stdout", NULL, NULL);
+ qh ferr= qh fout;
+ qhmem.ferr= qh fout;
+ }
+ break;
+ case 'C':
+ if (!isdigit(*s))
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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 (s[0] != ' ' || s[1] == '\"' || s[1] == '\'' ||isspace (s[1])) {
+ s++;
+ fprintf (qh ferr, "qhull warning: option 'TI' mistyped.\nUse 'TI', one space, file name, and space or end-of-line.\nDo not use quotes. Option 'FI' ignored.\n");
+ }else { /* not a procedure because of qh_option (filename, NULL, NULL); */
+ char filename[500], *t= filename;
+
+ s++;
+ while (*s) {
+ if (t - filename >= sizeof (filename)-2) {
+ fprintf (qh ferr, "qhull error: filename for 'TI' too long.\n");
+ qh_errexit (qh_ERRinput, NULL, NULL);
+ }
+ if (isspace (*s))
+ break;
+ *(t++)= *s++;
+ }
+ *t= '\0';
+ if (!freopen (filename, "r", stdin)) {
+ fprintf (qh ferr, "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 (s[0] != ' ' || s[1] == '\"' || isspace (s[1])) {
+ s++;
+ fprintf (qh ferr, "qhull warning: option 'TO' mistyped.\nUse 'TO', one space, file name, and space or end-of-line.\nThe file name may be enclosed in single quotes.\nDo not use double quotes. Option 'FO' ignored.\n");
+ }else { /* not a procedure because of qh_option (filename, NULL, NULL); */
+ char filename[500], *t= filename;
+ boolT isquote= False;
+
+ s++;
+ if (*s == '\'') {
+ isquote= True;
+ s++;
+ }
+ while (*s) {
+ if (t - filename >= sizeof (filename)-2) {
+ fprintf (qh ferr, "qhull error: filename for 'TO' too long.\n");
+ qh_errexit (qh_ERRinput, NULL, NULL);
+ }
+ if (isquote) {
+ if (*s == '\'') {
+ s++;
+ isquote= False;
+ break;
+ }
+ }else if (isspace (*s))
+ break;
+ *(t++)= *s++;
+ }
+ *t= '\0';
+ if (isquote)
+ fprintf (qh ferr, "qhull error: missing end quote for option 'TO'. Rest of line ignored.\n");
+ else if (!freopen (filename, "w", stdout)) {
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "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))
+ fprintf (qh ferr, "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--;
+ fprintf (qh ferr, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);
+ while (*++s && !isspace(*s));
+ break;
+ }
+ }
+ break;
+ default:
+ fprintf (qh ferr, "qhull warning: unknown flag %c (%x)\n", (int)s[-1],
+ (int)s[-1]);
+ break;
+ }
+ if (s-1 == prev_s && *s && !isspace(*s)) {
+ fprintf (qh ferr, "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 (isgeom && !qh FORCEoutput && qh PRINTout[1])
+ fprintf (qh ferr, "qhull warning: additional output formats are not compatible with Geomview\n");
+ /* set derived values in qh_initqhull_globals */
+} /* initflags */
+
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="initqhull_buffers">-</a>
+
+ 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 coplanarset= 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--; ) {
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="initqhull_globals">-</a>
+
+ 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)
+ test for qh.PRINTgood (i.e., only print 'good' facets)
+ initialize qh.CENTERtype, qh.normal_size,
+ qh.center_size, qh.TRACEpoint/level,
+ initialize and test random numbers
+ check for conflicting print output options
+*/
+void qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc) {
+ int seed, pointsneeded, extra= 0, i, randi, k;
+ boolT printgeom= False, printmath= False, printcoplanar= False;
+ realT randr;
+ realT factorial;
+
+ time_t timedata;
+
+ trace0((qh ferr, "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)
+ fprintf(qh ferr, "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)
+ fprintf(qh ferr, "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) {
+ fprintf (qh ferr, "qhull input error: merging not installed (qh_NOmerge + 'Qx', 'Cn' or 'An')\n");
+ qh_errexit (qh_ERRinput, NULL, NULL);
+ }
+#endif
+ 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 DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) {
+ qh KEEPinside= True;
+ qh_option ("Qinterior-keep", NULL, NULL);
+ }
+ if (qh DELAUNAY && qh HALFspace) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "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) {
+ fprintf(qh ferr, "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++;
+ extra= 1;
+ }
+ }
+ if (qh hull_dim <= 1) {
+ fprintf(qh ferr, "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, "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) {
+ fprintf (qh ferr, "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= 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) {
+ fprintf (qh ferr, "\
+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/10
+ || randr > qh_RANDOMmax * 5)
+ fprintf (qh ferr, "\
+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/2.0, qh_RANDOMmax);
+ qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
+ qh RANDOMb= 1.0 - qh RANDOMfactor;
+ if (qh_HASHfactor < 1.1) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr,"qhull input error: not enough points (%d) to construct initial simplex (need %d)\n",
+ numpoints, pointsneeded);
+ qh_errexit(qh_ERRinput, NULL, NULL);
+ }
+ if (qh PRINTtransparent) {
+ if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) {
+ fprintf(qh ferr,"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)
+ 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) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
+ }
+ if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) {
+ if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) {
+ qh KEEPcoplanar = True;
+ qh_option ("Qcoplanar", NULL, NULL);
+ }
+ }
+ if (printmath && (qh hull_dim > 3 || qh VORONOI)) {
+ fprintf (qh ferr, "qhull input error: Mathematica 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) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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;
+ }
+ }
+ 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)
+ fprintf (qh ferr, "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;
+ }
+} /* initqhull_globals */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="initqhull_mem">-</a>
+
+ 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(sizeof(vertexT));
+ if (qh MERGING) {
+ qh_memsize(sizeof(ridgeT));
+ qh_memsize(sizeof(mergeT));
+ }
+ qh_memsize(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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="initqhull_start">-</a>
+
+ qh_initqhull_start( infile, outfile, errfile )
+ start initialization of qhull
+ initialize statistics, stdio, default values for global variables
+
+ see:
+ qh_maxmin() determines the precision constants
+*/
+void qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile) {
+
+ qh_CPUclock; /* start the clock */
+#if qh_QHpointer
+ if (!(qh_qh= (qhT *)malloc (sizeof(qhT)))) {
+ fprintf (errfile, "qhull error (qh_initqhull_globals): insufficient memory\n");
+ exit (qh_ERRmem); /* no error handler */
+ }
+ memset((char *)qh_qh, 0, sizeof(qhT)); /* every field is 0, FALSE, NULL */
+#else
+ memset((char *)&qh_qh, 0, sizeof(qhT));
+#endif
+ strcat (qh qhull, "qhull");
+ qh_initstatistics();
+ 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 */
+ qh_RANDOMseed_(1);
+} /* initqhull_start */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="initthresholds">-</a>
+
+ 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 index, maxdim, k;
+ char *s= command;
+ 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)) {
+ fprintf(qh ferr, "qhull warning: no dimension given for Print option '%c' at: %s. Ignored\n",
+ key, s-1);
+ continue;
+ }
+ index= qh_strtol (s, &s);
+ if (index >= qh hull_dim) {
+ fprintf(qh ferr, "qhull warning: dimension %d for Print option '%c' is >= %d. Ignored\n",
+ index, key, qh hull_dim);
+ continue;
+ }
+ if (*s == ':') {
+ s++;
+ value= qh_strtod(s, &s);
+ if (fabs((double)value) > 1.0) {
+ fprintf(qh ferr, "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[index]= value;
+ else
+ qh upper_threshold[index]= 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)) {
+ fprintf(qh ferr, "qhull warning: no dimension given for Qhull option %c. Ignored\n",
+ key);
+ continue;
+ }
+ index= qh_strtol (s, &s);
+ if (index >= maxdim) {
+ fprintf(qh ferr, "qhull warning: dimension %d for Qhull option %c is >= %d. Ignored\n",
+ index, 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[index]= value;
+ else
+ qh upper_bound[index]= 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="option">-</a>
+
+ qh_option( option, intVal, realVal )
+ add an option description to qh.qhull_options
+
+ notes:
+ will be printed with statistics ('Ts') and errors
+ strlen(option) < 40
+*/
+void qh_option (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= strlen(buf);
+ qh qhull_optionlen += len;
+ maxlen= sizeof (qh qhull_options) - len -1;
+ maximize_(maxlen, 0);
+ if (qh qhull_optionlen >= 80 && maxlen > 0) {
+ qh qhull_optionlen= len;
+ strncat (qh qhull_options, "\n", maxlen--);
+ }
+ strncat (qh qhull_options, buf, maxlen);
+} /* option */
+
+#if qh_QHpointer
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="restore_qhull">-</a>
+
+ qh_restore_qhull( oldqh )
+ restores a previously saved qhull
+ also restores qh_qhstat and qhmem.tempstack
+
+ 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()
+*/
+void qh_restore_qhull (qhT **oldqh) {
+
+ if (*oldqh && strcmp ((*oldqh)->qhull, "qhull")) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n",
+ *oldqh);
+ qh_errexit (qh_ERRqhull, NULL, NULL);
+ }
+ if (qh_qh) {
+ fprintf (qhmem.ferr, "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) {
+ fprintf (qhmem.ferr, "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;
+ trace1((qh ferr, "qh_restore_qhull: restored qhull from %p\n", *oldqh));
+} /* restore_qhull */
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="save_qhull">-</a>
+
+ 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, "qh_save_qhull: save qhull %p\n", qh_qh));
+ if (!qh_qh) {
+ fprintf (qhmem.ferr, "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
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="strtol">-</a>
+
+ qh_strtol( s, endp) qh_strtod( s, endp)
+ internal versions of strtol() and strtod()
+ does not skip trailing spaces
+ notes:
+ some implementations of strtol()/strtod() skip trailing spaces
+*/
+double qh_strtod (const char *s, char **endp) {
+ double result;
+
+ result= strtod (s, endp);
+ if (s < (*endp) && (*endp)[-1] == ' ')
+ (*endp)--;
+ return result;
+} /* strtod */
+
+int qh_strtol (const char *s, char **endp) {
+ int result;
+
+ result= (int) strtol (s, endp, 10);
+ if (s< (*endp) && (*endp)[-1] == ' ')
+ (*endp)--;
+ return result;
+} /* strtol */
diff --git a/extern/qhull/src/io.c b/extern/qhull/src/io.c
new file mode 100755
index 00000000000..79ca7995d1e
--- /dev/null
+++ b/extern/qhull/src/io.c
@@ -0,0 +1,4089 @@
+/*<html><pre> -<a href="qh-io.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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-2002 The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*========= -prototypes for internal functions ========= */
+
+static int qh_compare_facetarea(const void *p1, const void *p2);
+static int qh_compare_facetmerge(const void *p1, const void *p2);
+static int qh_compare_facetvisit(const void *p1, const void *p2);
+int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */
+
+/*========= -functions in alphabetical order after qh_produce_output() =====*/
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="produce_output">-</a>
+
+ qh_produce_output()
+ prints out the result of qhull in desired format
+ 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 i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
+
+ if (qh VORONOI) {
+ qh_clearcenters (qh_ASvoronoi);
+ qh_vertexneighbors();
+ }
+ if (qh TRIangulate) {
+ 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 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_collectstatistics();
+ qh_printstatistics(qh ferr, "");
+ qh_memstatistics (qh ferr);
+ d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
+ fprintf(qh ferr, "\
+ size in bytes: merge %d ridge %d vertex %d facet %d\n\
+ normal %d ridge vertices %d facet vertices or neighbors %d\n",
+ sizeof(mergeT), sizeof(ridgeT),
+ sizeof(vertexT), sizeof(facetT),
+ qh normal_size, d_1, d_1 + SETelemsize);
+ }
+ if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
+ fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
+ qh_setsize ((setT*)qhmem.tempstack));
+ qh_errexit (qh_ERRqhull, NULL, NULL);
+ }
+} /* produce_output */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="dfacet">-</a>
+
+ dfacet( id )
+ print facet by id, for debugging
+
+*/
+void dfacet (unsigned id) {
+ facetT *facet;
+
+ FORALLfacets {
+ if (facet->id == id) {
+ qh_printfacet (qh fout, facet);
+ break;
+ }
+ }
+} /* dfacet */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="dvertex">-</a>
+
+ dvertex( id )
+ print vertex by id, for debugging
+*/
+void dvertex (unsigned id) {
+ vertexT *vertex;
+
+ FORALLvertices {
+ if (vertex->id == id) {
+ qh_printvertex (qh fout, vertex);
+ break;
+ }
+ }
+} /* dvertex */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="compare_vertexpoint">-</a>
+
+ qh_compare_vertexpoint( p1, p2 )
+ used by qsort() to order vertices by point id
+*/
+int qh_compare_vertexpoint(const void *p1, const void *p2) {
+ vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
+
+ return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
+} /* compare_vertexpoint */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="compare_facetarea">-</a>
+
+ qh_compare_facetarea( p1, p2 )
+ used by qsort() to order facets by area
+*/
+static int qh_compare_facetarea(const void *p1, const void *p2) {
+ facetT *a= *((facetT **)p1), *b= *((facetT **)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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="compare_facetmerge">-</a>
+
+ qh_compare_facetmerge( p1, p2 )
+ used by qsort() to order facets by number of merges
+*/
+static int qh_compare_facetmerge(const void *p1, const void *p2) {
+ facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+
+ return (a->nummerge - b->nummerge);
+} /* compare_facetvisit */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="compare_facetvisit">-</a>
+
+ qh_compare_facetvisit( p1, p2 )
+ used by qsort() to order facets by visit id or id
+*/
+static int qh_compare_facetvisit(const void *p1, const void *p2) {
+ facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+ int i,j;
+
+ if (!(i= a->visitid))
+ i= - a->id; /* do not convert to int */
+ if (!(j= b->visitid))
+ j= - b->id;
+ return (i - j);
+} /* compare_facetvisit */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="countfacets">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="detvnorm">-</a>
+
+ 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 {
+ fprintf(qh ferr, "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, "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, "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, "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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="detvridge">-</a>
+
+ 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 (&centers, neighbor);
+ }else if (firstinf) {
+ firstinf= False;
+ qh_setappend (&centers, neighbor);
+ }
+ }
+ }
+ qsort (SETaddr_(centers, facetT), qh_setsize (centers),
+ sizeof (facetT *), qh_compare_facetvisit);
+ qh_settempfree (&tricenters);
+ return centers;
+} /* detvridge */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="detvridge3">-</a>
+
+ 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 (not 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 (&centers, facet);
+ }else if (firstinf) {
+ firstinf= False;
+ qh_setappend (&centers, 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) {
+ fprintf (stderr, "qh_detvridge3: neigbors 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="eachvoronoi">-</a>
+
+ 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, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
+ count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
+ if (printvridge) {
+ 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 (&centers);
+ }
+ }
+ }
+ }
+ }
+ }
+ FOREACHneighbor_(atvertex)
+ neighbor->seen= False;
+ qh_settempfree (&tricenters);
+ return totridges;
+} /* eachvoronoi */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="eachvoronoi_all">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="facet2point">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="facetvertices">-</a>
+
+ 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 */
+
+/*-<a href="qh-geom.htm#TOC"
+ >-------------------------------</a><a name="geomplanes">-</a>
+
+ 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 (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 */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="markkeep">-</a>
+
+ qh_markkeep( facetlist )
+ mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
+ ignores visible facets (not 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, "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,
+ 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,
+ 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 */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="markvoronoi">-</a>
+
+ 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, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
+ return vertices;
+} /* markvoronoi */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="order_vertexneighbors">-</a>
+
+ 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, "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) {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printafacet">-</a>
+
+ 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, int 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) {
+ fprintf (fp, qh_REAL_1, facet->f.area);
+ fprintf (fp, "\n");
+ }else
+ fprintf (fp, "0\n");
+ break;
+ case qh_PRINTcoplanars:
+ fprintf (fp, "%d", qh_setsize (facet->coplanarset));
+ FOREACHpoint_(facet->coplanarset)
+ fprintf (fp, " %d", qh_pointid (point));
+ fprintf (fp, "\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:
+ fprintf (fp, "%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:
+ fprintf (fp, "%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) {
+ fprintf (fp, "no normal for facet f%d\n", facet->id);
+ break;
+ }
+ if (qh CDDoutput) {
+ fprintf (fp, qh_REAL_1, -offset);
+ for (k=0; k < qh hull_dim; k++)
+ fprintf (fp, qh_REAL_1, -facet->normal[k]);
+ }else {
+ for (k=0; k < qh hull_dim; k++)
+ fprintf (fp, qh_REAL_1, facet->normal[k]);
+ fprintf (fp, qh_REAL_1, offset);
+ }
+ fprintf (fp, "\n");
+ break;
+ case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */
+ if (qh hull_dim == 2)
+ qh_printfacet2math (fp, facet, qh printoutvar++);
+ else
+ qh_printfacet3math (fp, facet, qh printoutvar++);
+ break;
+ case qh_PRINTneighbors:
+ fprintf (fp, "%d", qh_setsize (facet->neighbors));
+ FOREACHneighbor_(facet)
+ fprintf (fp, " %d",
+ neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
+ fprintf (fp, "\n");
+ break;
+ case qh_PRINTpointintersect:
+ if (!qh feasible_point) {
+ fprintf (fp, "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--; )
+ fprintf (fp, qh_REAL_1, qh_INFINITE);
+ fprintf (fp, "\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);
+ fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
+ }
+ break;
+ case qh_PRINTpoints: /* VORONOI only by qh_printbegin */
+ if (qh CDDoutput)
+ fprintf (fp, "1 ");
+ qh_printcenter (fp, format, NULL, facet);
+ break;
+ case qh_PRINTvertices:
+ fprintf (fp, "%d", qh_setsize (facet->vertices));
+ FOREACHvertex_(facet->vertices)
+ fprintf (fp, " %d", qh_pointid (vertex->point));
+ fprintf (fp, "\n");
+ break;
+ }
+} /* printafacet */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printbegin">-</a>
+
+ 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, int 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:
+ fprintf (fp, "%d\n", numfacets);
+ break;
+ case qh_PRINTcoplanars:
+ fprintf (fp, "%d\n", numfacets);
+ break;
+ case qh_PRINTcentrums:
+ if (qh CENTERtype == qh_ASnone)
+ qh_clearcenters (qh_AScentrum);
+ fprintf (fp, "%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))
+ fprintf (qh ferr, "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)))
+ fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
+ if (qh PRINTdim == 4 && (qh PRINTspheres))
+ fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
+ if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
+ fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
+ if (qh PRINTdim == 2) {
+ fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
+ qh rbox_command, qh qhull_command);
+ }else if (qh PRINTdim == 3) {
+ fprintf(fp, "{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 */
+ fprintf (fp, "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)
+ fprintf (fp, "4VECT %d %d 1\n", num, num);
+ else
+ fprintf (fp, "VECT %d %d 1\n", num, num);
+ for (i= num; i--; ) {
+ if (i % 20 == 0)
+ fprintf (fp, "\n");
+ fprintf (fp, "1 ");
+ }
+ fprintf (fp, "# 1 point per line\n1 ");
+ for (i= num-1; i--; ) {
+ if (i % 20 == 0)
+ fprintf (fp, "\n");
+ fprintf (fp, "0 ");
+ }
+ fprintf (fp, "# 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);
+ }
+ fprintf (fp, "0 1 1 1 # color of points\n");
+ }
+ if (qh PRINTdim == 4 && !qh PRINTnoplanes)
+ /* 4dview loads up multiple 4OFF objects slowly */
+ fprintf(fp, "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 (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:
+ fprintf (fp, "%d\n", numfacets);
+ break;
+ case qh_PRINTincidences:
+ if (qh VORONOI && qh PRINTprecision)
+ fprintf (qh ferr, "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)
+ fprintf(fp, "%d\n", numfacets);
+ else
+ fprintf(fp, "%d\n", numsimplicial+numridges);
+ break;
+ case qh_PRINTinner:
+ case qh_PRINTnormals:
+ case qh_PRINTouter:
+ if (qh CDDoutput)
+ fprintf (fp, "%s | %s\nbegin\n %d %d real\n", qh rbox_command,
+ qh qhull_command, numfacets, qh hull_dim+1);
+ else
+ fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
+ break;
+ case qh_PRINTmathematica:
+ if (qh hull_dim > 3) /* qh_initbuffers also checks */
+ goto LABELnoformat;
+ if (qh VORONOI)
+ fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
+ fprintf(fp, "{\n");
+ qh printoutvar= 0; /* counts number of facets for notfirst */
+ break;
+ case qh_PRINTmerges:
+ fprintf (fp, "%d\n", numfacets);
+ break;
+ case qh_PRINTpointintersect:
+ fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
+ break;
+ case qh_PRINTneighbors:
+ fprintf (fp, "%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)
+ fprintf (fp, "%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 */
+ fprintf (fp, "%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:
+ fprintf (fp, "%d\n", numcoplanars);
+ break;
+ case qh_PRINTpoints:
+ if (!qh VORONOI)
+ goto LABELnoformat;
+ if (qh CDDoutput)
+ fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
+ qh qhull_command, numfacets, qh hull_dim);
+ else
+ fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
+ break;
+ case qh_PRINTvertices:
+ fprintf (fp, "%d\n", numfacets);
+ break;
+ case qh_PRINTsummary:
+ default:
+ LABELnoformat:
+ fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
+ qh hull_dim);
+ qh_errexit (qh_ERRqhull, NULL, NULL);
+ }
+} /* printbegin */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printcenter">-</a>
+
+ 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
+*/
+void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
+ int k, num;
+
+ if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
+ return;
+ if (string)
+ fprintf (fp, string, facet->id);
+ 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++)
+ fprintf (fp, qh_REAL_1, facet->center[k]);
+ }else {
+ for (k=0; k < num; k++)
+ fprintf (fp, 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++)
+ fprintf (fp, qh_REAL_1, facet->center[k]);
+ }
+ if (format == qh_PRINTgeom && num == 2)
+ fprintf (fp, " 0\n");
+ else
+ fprintf (fp, "\n");
+} /* printcenter */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printcentrum">-</a>
+
+ 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;
+ }
+ fprintf (fp, "{appearance {-normal -edge normscale 0} ");
+ if (qh firstcentrum) {
+ qh firstcentrum= False;
+ fprintf (fp, "{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
+ fprintf (fp, "{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);
+ fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
+ fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
+ fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
+ qh_printpoint3 (fp, centrum);
+ fprintf (fp, "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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printend">-</a>
+
+ qh_printend( fp, format )
+ prints trailer for all output formats
+
+ see:
+ qh_printbegin() and qh_printafacet()
+
+*/
+void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+ int num;
+ facetT *facet, **facetp;
+
+ if (!qh printoutnum)
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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
+ fprintf(fp, "}\n");
+ break;
+ case qh_PRINTinner:
+ case qh_PRINTnormals:
+ case qh_PRINTouter:
+ if (qh CDDoutput)
+ fprintf (fp, "end\n");
+ break;
+ case qh_PRINTmathematica:
+ fprintf(fp, "}\n");
+ break;
+ case qh_PRINTpoints:
+ if (qh CDDoutput)
+ fprintf (fp, "end\n");
+ break;
+ }
+} /* printend */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printend4geom">-</a>
+
+ 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)
+ fprintf (fp, "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)
+ fprintf (fp, "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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printextremes">-</a>
+
+ 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, int 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);
+ fprintf (fp, "%d\n", numpoints);
+ FOREACHpoint_i_(points) {
+ if (point)
+ fprintf (fp, "%d\n", point_i);
+ }
+ qh_settempfree (&points);
+} /* printextremes */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printextremes_2d">-</a>
+
+ 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, int 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);
+ fprintf(fp, "%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) {
+ fprintf(qh ferr, "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;
+ fprintf(fp, "%d\n", qh_pointid (vertexA->point));
+ }
+ if (vertexB->visitid != qh vertex_visit) {
+ vertexB->visitid= qh vertex_visit;
+ fprintf(fp, "%d\n", qh_pointid (vertexB->point));
+ }
+ }
+ facet->visitid= qh visit_id;
+ facet= nextfacet;
+ }while (facet && facet != startfacet);
+} /* printextremes_2d */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printextremes_d">-</a>
+
+ 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, int 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;
+ }
+ fprintf (fp, "%d\n", numpoints);
+ FOREACHvertex_(vertices) {
+ if (vertex->seen)
+ fprintf (fp, "%d\n", qh_pointid (vertex->point));
+ }
+ qh_settempfree (&vertices);
+} /* printextremes_d */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet2geom">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet2geom_points">-</a>
+
+ 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;
+
+ fprintf(fp, "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);
+ }
+ fprintf(fp, "%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);
+ }
+ fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printfacet2geom_points */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet2math">-</a>
+
+ qh_printfacet2math( fp, facet, notfirst )
+ print 2-d Mathematica output for a facet
+ may be non-simplicial
+
+ notes:
+ use %16.8f since Mathematica 2.2 does not handle exponential format
+*/
+void qh_printfacet2math(FILE *fp, facetT *facet, int notfirst) {
+ pointT *point0, *point1;
+ realT mindist;
+
+ qh_facet2point (facet, &point0, &point1, &mindist);
+ if (notfirst)
+ fprintf(fp, ",");
+ fprintf(fp, "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n",
+ point0[0], point0[1], point1[0], point1[1]);
+ qh_memfree (point1, qh normal_size);
+ qh_memfree (point0, qh normal_size);
+} /* printfacet2math */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet3geom_points">-</a>
+
+ 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;
+
+ fprintf(fp, "{ 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)
+ fprintf(fp, "0 ");
+ else
+ fprintf(fp, "%8.4g ", point[k]);
+ }
+ if (printpoints != points)
+ qh_memfree (point, qh normal_size);
+ fprintf (fp, "\n");
+ }
+ if (printpoints != points)
+ qh_settempfree (&printpoints);
+ fprintf(fp, "%d ", n);
+ for(i= 0; i < n; i++)
+ fprintf(fp, "%d ", i);
+ fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
+} /* printfacet3geom_points */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet3geom_simplicial">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet3math">-</a>
+
+ qh_printfacet3math( fp, facet, notfirst )
+ print 3-d Mathematica output for a facet
+
+ notes:
+ may be non-simplicial
+ use %16.8f since Mathematica 2.2 does not handle exponential format
+*/
+void qh_printfacet3math (FILE *fp, facetT *facet, int notfirst) {
+ vertexT *vertex, **vertexp;
+ setT *points, *vertices;
+ pointT *point, **pointp;
+ boolT firstpoint= True;
+ realT dist;
+
+ if (notfirst)
+ fprintf(fp, ",\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);
+ }
+ fprintf(fp, "Polygon[{");
+ FOREACHpoint_(points) {
+ if (firstpoint)
+ firstpoint= False;
+ else
+ fprintf(fp, ",\n");
+ fprintf(fp, "{%16.8f, %16.8f, %16.8f}", point[0], point[1], point[2]);
+ }
+ FOREACHpoint_(points)
+ qh_memfree (point, qh normal_size);
+ qh_settempfree(&points);
+ qh_settempfree(&vertices);
+ fprintf(fp, "}]");
+} /* printfacet3math */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet3vertex">-</a>
+
+ 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, int format) {
+ vertexT *vertex, **vertexp;
+ setT *vertices;
+
+ vertices= qh_facet3vertex (facet);
+ if (format == qh_PRINToff)
+ fprintf (fp, "%d ", qh_setsize (vertices));
+ FOREACHvertex_(vertices)
+ fprintf (fp, "%d ", qh_pointid(vertex->point));
+ fprintf (fp, "\n");
+ qh_settempfree(&vertices);
+} /* printfacet3vertex */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>
+
+ 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)
+ fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
+ else {
+ qh printoutvar++;
+ fprintf (fp, "# 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)
+ fprintf(fp, "%8.4g ", point[k]);
+ }
+ fprintf (fp, "\n");
+ qh_memfree (point, qh normal_size);
+ }
+ if (qh DROPdim >= 0)
+ fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+ }
+ }
+} /* printfacet4geom_nonsimplicial */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacet4geom_simplicial">-</a>
+
+ 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)
+ fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
+ facet->id, neighbor->id);
+ else {
+ qh printoutvar++;
+ fprintf (fp, "# 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)
+ fprintf(fp, "%8.4g ", vertex->point[k]);
+ }
+ fprintf (fp, "\n");
+ }
+ if (qh DROPdim >= 0)
+ fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+ }
+ qh_setfree(&vertices);
+ }
+} /* printfacet4geom_simplicial */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>
+
+ 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, int format) {
+ vertexT *vertex, **vertexp;
+ ridgeT *ridge, **ridgep;
+
+ if (facet->visible && qh NEWfacets)
+ return;
+ FOREACHridge_(facet->ridges) {
+ if (format == qh_PRINTtriangles)
+ fprintf(fp, "%d ", qh hull_dim);
+ fprintf(fp, "%d ", id);
+ if ((ridge->top == facet) ^ qh_ORIENTclock) {
+ FOREACHvertex_(ridge->vertices)
+ fprintf(fp, "%d ", qh_pointid(vertex->point));
+ }else {
+ FOREACHvertexreverse12_(ridge->vertices)
+ fprintf(fp, "%d ", qh_pointid(vertex->point));
+ }
+ fprintf(fp, "\n");
+ }
+} /* printfacetNvertex_nonsimplicial */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>
+
+ 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, int format) {
+ vertexT *vertex, **vertexp;
+
+ if (format == qh_PRINToff || format == qh_PRINTtriangles)
+ fprintf (fp, "%d ", qh_setsize (facet->vertices));
+ if ((facet->toporient ^ qh_ORIENTclock)
+ || (qh hull_dim > 2 && !facet->simplicial)) {
+ FOREACHvertex_(facet->vertices)
+ fprintf(fp, "%d ", qh_pointid(vertex->point));
+ }else {
+ FOREACHvertexreverse12_(facet->vertices)
+ fprintf(fp, "%d ", qh_pointid(vertex->point));
+ }
+ fprintf(fp, "\n");
+} /* printfacetNvertex_simplicial */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacetheader">-</a>
+
+ qh_printfacetheader( fp, facet )
+ prints header fields of a facet to fp
+
+ notes:
+ for 'f' output and debugging
+*/
+void qh_printfacetheader(FILE *fp, facetT *facet) {
+ pointT *point, **pointp, *furthest;
+ facetT *neighbor, **neighborp;
+ realT dist;
+
+ if (facet == qh_MERGEridge) {
+ fprintf (fp, " MERGEridge\n");
+ return;
+ }else if (facet == qh_DUPLICATEridge) {
+ fprintf (fp, " DUPLICATEridge\n");
+ return;
+ }else if (!facet) {
+ fprintf (fp, " NULLfacet\n");
+ return;
+ }
+ qh old_randomdist= qh RANDOMdist;
+ qh RANDOMdist= False;
+ fprintf(fp, "- f%d\n", facet->id);
+ fprintf(fp, " - flags:");
+ if (facet->toporient)
+ fprintf(fp, " top");
+ else
+ fprintf(fp, " bottom");
+ if (facet->simplicial)
+ fprintf(fp, " simplicial");
+ if (facet->tricoplanar)
+ fprintf(fp, " tricoplanar");
+ if (facet->upperdelaunay)
+ fprintf(fp, " upperDelaunay");
+ if (facet->visible)
+ fprintf(fp, " visible");
+ if (facet->newfacet)
+ fprintf(fp, " new");
+ if (facet->tested)
+ fprintf(fp, " tested");
+ if (!facet->good)
+ fprintf(fp, " notG");
+ if (facet->seen)
+ fprintf(fp, " seen");
+ if (facet->coplanar)
+ fprintf(fp, " coplanar");
+ if (facet->mergehorizon)
+ fprintf(fp, " mergehorizon");
+ if (facet->keepcentrum)
+ fprintf(fp, " keepcentrum");
+ if (facet->dupridge)
+ fprintf(fp, " dupridge");
+ if (facet->mergeridge && !facet->mergeridge2)
+ fprintf(fp, " mergeridge1");
+ if (facet->mergeridge2)
+ fprintf(fp, " mergeridge2");
+ if (facet->newmerge)
+ fprintf(fp, " newmerge");
+ if (facet->flipped)
+ fprintf(fp, " flipped");
+ if (facet->notfurthest)
+ fprintf(fp, " notfurthest");
+ if (facet->degenerate)
+ fprintf(fp, " degenerate");
+ if (facet->redundant)
+ fprintf(fp, " redundant");
+ fprintf(fp, "\n");
+ if (facet->isarea)
+ fprintf(fp, " - area: %2.2g\n", facet->f.area);
+ else if (qh NEWfacets && facet->visible && facet->f.replace)
+ fprintf(fp, " - replacement: f%d\n", facet->f.replace->id);
+ else if (facet->newfacet) {
+ if (facet->f.samecycle && facet->f.samecycle != facet)
+ fprintf(fp, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
+ }else if (facet->tricoplanar /* !isarea */) {
+ if (facet->f.triowner)
+ fprintf(fp, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
+ }else if (facet->f.newcycle)
+ fprintf(fp, " - was horizon to f%d\n", facet->f.newcycle->id);
+ if (facet->nummerge)
+ fprintf(fp, " - merges: %d\n", facet->nummerge);
+ qh_printpointid(fp, " - normal: ", qh hull_dim, facet->normal, -1);
+ fprintf(fp, " - 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)
+ fprintf(fp, " - maxoutside: %10.7g\n", facet->maxoutside);
+#endif
+ if (!SETempty_(facet->outsideset)) {
+ furthest= (pointT*)qh_setlast(facet->outsideset);
+ if (qh_setsize (facet->outsideset) < 6) {
+ fprintf(fp, " - 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 {
+ fprintf(fp, " - outside set: %d points.", qh_setsize(facet->outsideset));
+ qh_printpoint(fp, " Furthest", furthest);
+ }
+#if !qh_COMPUTEfurthest
+ fprintf(fp, " - furthest distance= %2.2g\n", facet->furthestdist);
+#endif
+ }
+ if (!SETempty_(facet->coplanarset)) {
+ furthest= (pointT*)qh_setlast(facet->coplanarset);
+ if (qh_setsize (facet->coplanarset) < 6) {
+ fprintf(fp, " - 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 {
+ fprintf(fp, " - coplanar set: %d points.", qh_setsize(facet->coplanarset));
+ qh_printpoint(fp, " Furthest", furthest);
+ }
+ zinc_(Zdistio);
+ qh_distplane (furthest, facet, &dist);
+ fprintf(fp, " furthest distance= %2.2g\n", dist);
+ }
+ qh_printvertices (fp, " - vertices:", facet->vertices);
+ fprintf(fp, " - neighboring facets: ");
+ FOREACHneighbor_(facet) {
+ if (neighbor == qh_MERGEridge)
+ fprintf(fp, " MERGE");
+ else if (neighbor == qh_DUPLICATEridge)
+ fprintf(fp, " DUP");
+ else
+ fprintf(fp, " f%d", neighbor->id);
+ }
+ fprintf(fp, "\n");
+ qh RANDOMdist= qh old_randomdist;
+} /* printfacetheader */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacetridges">-</a>
+
+ qh_printfacetridges( fp, facet )
+ prints ridges of a facet to fp
+
+ notes:
+ ridges printed in neighbor order
+ assumes the ridges exist
+ for 'f' output
+*/
+void qh_printfacetridges(FILE *fp, facetT *facet) {
+ facetT *neighbor, **neighborp;
+ ridgeT *ridge, **ridgep;
+ int numridges= 0;
+
+
+ if (facet->visible && qh NEWfacets) {
+ fprintf(fp, " - ridges (ids may be garbage):");
+ FOREACHridge_(facet->ridges)
+ fprintf(fp, " r%d", ridge->id);
+ fprintf(fp, "\n");
+ }else {
+ fprintf(fp, " - 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)) {
+ fprintf (fp, " - all ridges:");
+ FOREACHridge_(facet->ridges)
+ fprintf (fp, " r%d", ridge->id);
+ fprintf (fp, "\n");
+ }
+ FOREACHridge_(facet->ridges) {
+ if (!ridge->seen)
+ qh_printridge(fp, ridge);
+ }
+ }
+} /* printfacetridges */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printfacets">-</a>
+
+ 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, int 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))
+ fprintf (qh ferr, "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);
+ fprintf (fp, "%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)
+ fprintf(fp, "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)
+ fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
+ else if (format == qh_PRINTsize) {
+ fprintf (fp, "0\n2 ");
+ fprintf (fp, qh_REAL_1, qh totarea);
+ fprintf (fp, qh_REAL_1, qh totvol);
+ fprintf (fp, "\n");
+ }else if (format == qh_PRINTsummary) {
+ qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
+ &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+ vertices= qh_facetvertices (facetlist, facets, printall);
+ fprintf (fp, "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);
+ fprintf (fp, 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 */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printhelp_degenerate">-</a>
+
+ qh_printhelp_degenerate( fp )
+ prints descriptive message for precision error
+
+ notes:
+ no message if qh_QUICKhelp
+*/
+void qh_printhelp_degenerate(FILE *fp) {
+
+ if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2)
+ fprintf(fp, "\n\
+A Qhull error has occurred. Qhull should have corrected the above\n\
+precision error. Please send the input and all of the output to\n\
+qhull_bug@geom.umn.edu\n");
+ else if (!qh_QUICKhelp) {
+ fprintf(fp, "\n\
+Precision problems were detected during construction of the convex hull.\n\
+This occurs because convex hull algorithms assume that calculations are\n\
+exact, but floating-point arithmetic has roundoff errors.\n\
+\n\
+To correct for precision problems, do not use 'Q0'. By default, Qhull\n\
+selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\
+Qhull joggles the input to prevent precision problems. See \"Imprecision\n\
+in Qhull\" (qh-impre.htm).\n\
+\n\
+If you use 'Q0', the output may include\n\
+coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\
+Qhull may produce a ridge with four neighbors or two facets with the same \n\
+vertices. Qhull reports these events when they occur. It stops when a\n\
+concave ridge, flipped facet, or duplicate facet occurs.\n");
+#if REALfloat
+ fprintf (fp, "\
+\n\
+Qhull is currently using single precision arithmetic. The following\n\
+will probably remove the precision problems:\n\
+ - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
+#endif
+ if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
+ fprintf( fp, "\
+\n\
+When computing the Delaunay triangulation of coordinates > 1.0,\n\
+ - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
+ if (qh DELAUNAY && !qh ATinfinity)
+ fprintf( fp, "\
+When computing the Delaunay triangulation:\n\
+ - use 'Qz' to add a point at-infinity. This reduces precision problems.\n");
+
+ fprintf(fp, "\
+\n\
+If you need triangular output:\n\
+ - use option 'Qt' to triangulate the output\n\
+ - use option 'QJ' to joggle the input points and remove precision errors\n\
+ - use option 'Ft'. It triangulates non-simplicial facets with added points.\n\
+\n\
+If you must use 'Q0',\n\
+try one or more of the following options. They can not guarantee an output.\n\
+ - use 'QbB' to scale the input to a cube.\n\
+ - use 'Po' to produce output and prevent partitioning for flipped facets\n\
+ - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
+ - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
+ - options 'Qf', 'Qbb', and 'QR0' may also help\n",
+ qh DISTround);
+ fprintf(fp, "\
+\n\
+To guarantee simplicial output:\n\
+ - use option 'Qt' to triangulate the output\n\
+ - use option 'QJ' to joggle the input points and remove precision errors\n\
+ - use option 'Ft' to triangulate the output by adding points\n\
+ - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
+");
+ }
+} /* printhelp_degenerate */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printhelp_singular">-</a>
+
+ qh_printhelp_singular( fp )
+ prints descriptive message for singular input
+*/
+void qh_printhelp_singular(FILE *fp) {
+ facetT *facet;
+ vertexT *vertex, **vertexp;
+ realT min, max, *coord, dist;
+ int i,k;
+
+ fprintf(fp, "\n\
+The input to qhull appears to be less than %d dimensional, or a\n\
+computation has overflowed.\n\n\
+Qhull could not construct a clearly convex simplex from points:\n",
+ qh hull_dim);
+ qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
+ if (!qh_QUICKhelp)
+ fprintf(fp, "\n\
+The center point is coplanar with a facet, or a vertex is coplanar\n\
+with a neighboring facet. The maximum round off error for\n\
+computing distances is %2.2g. The center point, facets and distances\n\
+to the center point are as follows:\n\n", qh DISTround);
+ qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
+ fprintf (fp, "\n");
+ FORALLfacets {
+ fprintf (fp, "facet");
+ FOREACHvertex_(facet->vertices)
+ fprintf (fp, " p%d", qh_pointid(vertex->point));
+ zinc_(Zdistio);
+ qh_distplane(qh interior_point, facet, &dist);
+ fprintf (fp, " distance= %4.2g\n", dist);
+ }
+ if (!qh_QUICKhelp) {
+ if (qh HALFspace)
+ fprintf (fp, "\n\
+These points are the dual of the given halfspaces. They indicate that\n\
+the intersection is degenerate.\n");
+ fprintf (fp,"\n\
+These points either have a maximum or minimum x-coordinate, or\n\
+they maximize the determinant for k coordinates. Trial points\n\
+are first selected from points that maximize a coordinate.\n");
+ if (qh hull_dim >= qh_INITIALmax)
+ fprintf (fp, "\n\
+Because of the high dimension, the min x-coordinate and max-coordinate\n\
+points are used if the determinant is non-zero. Option 'Qs' will\n\
+do a better, though much slower, job. Instead of 'Qs', you can change\n\
+the points by randomly rotating the input with 'QR0'.\n");
+ }
+ fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
+ for (k=0; k < qh hull_dim; k++) {
+ min= REALmax;
+ max= -REALmin;
+ for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
+ maximize_(max, *coord);
+ minimize_(min, *coord);
+ }
+ fprintf (fp, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);
+ }
+ if (!qh_QUICKhelp) {
+ fprintf (fp, "\n\
+If the input should be full dimensional, you have several options that\n\
+may determine an initial simplex:\n\
+ - use 'QJ' to joggle the input and make it full dimensional\n\
+ - use 'QbB' to scale the points to the unit cube\n\
+ - use 'QR0' to randomly rotate the input for different maximum points\n\
+ - use 'Qs' to search all points for the initial simplex\n\
+ - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
+ - trace execution with 'T3' to see the determinant for each point.\n",
+ qh DISTround);
+#if REALfloat
+ fprintf (fp, "\
+ - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
+#endif
+ fprintf (fp, "\n\
+If the input is lower dimensional:\n\
+ - use 'QJ' to joggle the input and make it full dimensional\n\
+ - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\
+ pick the coordinate with the least range. The hull will have the\n\
+ correct topology.\n\
+ - determine the flat containing the points, rotate the points\n\
+ into a coordinate plane, and delete the other coordinates.\n\
+ - add one or more points to make the input full dimensional.\n\
+");
+ if (qh DELAUNAY && !qh ATinfinity)
+ fprintf (fp, "\n\n\
+This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
+ - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
+ - or use 'QJ' to joggle the input and avoid co-circular data\n");
+ }
+} /* printhelp_singular */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printhyperplaneintersection">-</a>
+
+ 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)
+ fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
+ else if (qh hull_dim == 4 && qh DROPdim >= 0)
+ fprintf(fp, "OFF 3 1 1 ");
+ else
+ qh printoutvar++;
+ fprintf (fp, "# 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);
+ fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
+ }else
+ fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
+ if (nearzero1+nearzero2)
+ fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
+ else
+ fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
+ }
+ if (qh hull_dim == 3)
+ fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+ else if (qh hull_dim == 4 && qh DROPdim >= 0)
+ fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printhyperplaneintersection */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printline3geom">-</a>
+
+ 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)) {
+ fprintf (fp, "VECT 1 2 1 2 1\n");
+ for (k= 0; k < 3; k++)
+ fprintf (fp, "%8.4g ", pB[k]);
+ fprintf (fp, " # p%d\n", qh_pointid (pointB));
+ }else
+ fprintf (fp, "VECT 1 1 1 1 1\n");
+ for (k=0; k < 3; k++)
+ fprintf (fp, "%8.4g ", pA[k]);
+ fprintf (fp, " # p%d\n", qh_pointid (pointA));
+ fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
+}
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printneighborhood">-</a>
+
+ 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, int 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printpoint">-</a>
+
+ 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)
+*/
+void qh_printpoint(FILE *fp, char *string, pointT *point) {
+ int id= qh_pointid( point);
+
+ qh_printpointid( fp, string, qh hull_dim, point, id);
+} /* printpoint */
+
+void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
+ int k;
+ realT r; /*bug fix*/
+
+ if (!point)
+ return;
+ if (string) {
+ fputs (string, fp);
+ if (id != -1)
+ fprintf(fp, " p%d: ", id);
+ }
+ for(k= dim; k--; ) {
+ r= *point++;
+ if (string)
+ fprintf(fp, " %8.4g", r);
+ else
+ fprintf(fp, qh_REAL_1, r);
+ }
+ fprintf(fp, "\n");
+} /* printpointid */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printpoint3">-</a>
+
+ 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++)
+ fprintf (fp, "%8.4g ", p[k]);
+ fprintf (fp, " # p%d\n", qh_pointid (point));
+} /* printpoint3 */
+
+/*----------------------------------------
+-printpoints- print pointids for a set of points starting at index
+ see geom.c
+*/
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printpoints_out">-</a>
+
+ 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, int 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)
+ fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
+ qh qhull_command, numpoints, qh hull_dim + 1);
+ else
+ fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
+ FOREACHpoint_i_(points) {
+ if (point) {
+ if (qh CDDoutput)
+ fprintf (fp, "1 ");
+ qh_printpoint (fp, NULL, point);
+ }
+ }
+ if (qh CDDoutput)
+ fprintf (fp, "end\n");
+ qh_settempfree (&points);
+} /* printpoints_out */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printpointvect">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printpointvect2">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printridge">-</a>
+
+ qh_printridge( fp, ridge )
+ prints the information in a ridge
+
+ notes:
+ for qh_printfacetridges()
+*/
+void qh_printridge(FILE *fp, ridgeT *ridge) {
+
+ fprintf(fp, " - r%d", ridge->id);
+ if (ridge->tested)
+ fprintf (fp, " tested");
+ if (ridge->nonconvex)
+ fprintf (fp, " nonconvex");
+ fprintf (fp, "\n");
+ qh_printvertices (fp, " vertices:", ridge->vertices);
+ if (ridge->top && ridge->bottom)
+ fprintf(fp, " between f%d and f%d\n",
+ ridge->top->id, ridge->bottom->id);
+} /* printridge */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printspheres">-</a>
+
+ 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++;
+ fprintf (fp, "{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) {
+ fprintf(fp, "%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);
+ fprintf (fp, "1\n");
+ }
+ fprintf (fp, "}}}\n");
+} /* printspheres */
+
+
+/*----------------------------------------------
+-printsummary-
+ see qhull.c
+*/
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvdiagram">-</a>
+
+ 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, int 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 {
+ fprintf(qh ferr, "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);
+ fprintf (fp, "%d\n", totcount);
+ totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
+ qh_settempfree (&vertices);
+#if 0 /* for testing qh_eachvoronoi_all */
+ fprintf (fp, "\n");
+ totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
+ fprintf (fp, "%d\n", totcount);
+#endif
+} /* printvdiagram */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvdiagram2">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvertex">-</a>
+
+ qh_printvertex( fp, vertex )
+ prints the information in a vertex
+*/
+void qh_printvertex(FILE *fp, vertexT *vertex) {
+ pointT *point;
+ int k, count= 0;
+ facetT *neighbor, **neighborp;
+ realT r; /*bug fix*/
+
+ if (!vertex) {
+ fprintf (fp, " NULLvertex\n");
+ return;
+ }
+ fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
+ point= vertex->point;
+ if (point) {
+ for(k= qh hull_dim; k--; ) {
+ r= *point++;
+ fprintf(fp, " %5.2g", r);
+ }
+ }
+ if (vertex->deleted)
+ fprintf(fp, " deleted");
+ if (vertex->delridge)
+ fprintf (fp, " ridgedeleted");
+ fprintf(fp, "\n");
+ if (vertex->neighbors) {
+ fprintf(fp, " neighbors:");
+ FOREACHneighbor_(vertex) {
+ if (++count % 100 == 0)
+ fprintf (fp, "\n ");
+ fprintf(fp, " f%d", neighbor->id);
+ }
+ fprintf(fp, "\n");
+ }
+} /* printvertex */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvertexlist">-</a>
+
+ 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, char* string, facetT *facetlist,
+ setT *facets, boolT printall) {
+ vertexT *vertex, **vertexp;
+ setT *vertices;
+
+ vertices= qh_facetvertices (facetlist, facets, printall);
+ fputs (string, fp);
+ FOREACHvertex_(vertices)
+ qh_printvertex(fp, vertex);
+ qh_settempfree (&vertices);
+} /* printvertexlist */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvertices">-</a>
+
+ qh_printvertices( fp, string, vertices )
+ prints vertices in a set
+*/
+void qh_printvertices(FILE *fp, char* string, setT *vertices) {
+ vertexT *vertex, **vertexp;
+
+ fputs (string, fp);
+ FOREACHvertex_(vertices)
+ fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
+ fprintf(fp, "\n");
+} /* printvertices */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvneighbors">-</a>
+
+ 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 */
+ fprintf (fp, "%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);
+ fprintf (fp, "%d", numneighbors);
+ if (qh hull_dim == 3)
+ qh_order_vertexneighbors (vertex);
+ else if (qh hull_dim >= 4)
+ qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
+ sizeof (facetT *), qh_compare_facetvisit);
+ FOREACHneighbor_(vertex)
+ fprintf (fp, " %d",
+ neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
+ fprintf (fp, "\n");
+ }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
+ fprintf (fp, "1 %d\n",
+ facet->visitid ? facet->visitid - 1 : - facet->id);
+ else
+ fprintf (fp, "0\n");
+ }
+ qh_settempfree (&coplanar_points);
+ qh_settempfree (&vertex_points);
+ qh_settempfree (&vertices);
+} /* printvneighbors */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvoronoi">-</a>
+
+ 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, int 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)
+ fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
+ numcenters, numvertices);
+ else
+ fprintf (fp, "%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--; )
+ fprintf (fp, qh_REAL_1, 0.0);
+ fprintf (fp, " 0 # infinity not used\n");
+ }else {
+ for (k= qh hull_dim-1; k--; )
+ fprintf (fp, qh_REAL_1, qh_INFINITE);
+ fprintf (fp, "\n");
+ }
+ FORALLfacet_(facetlist) {
+ if (facet->visitid && facet->visitid < numfacets) {
+ if (format == qh_PRINTgeom)
+ fprintf (fp, "# %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)
+ fprintf (fp, "# %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, vertexT),
+ 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) {
+ fprintf (fp, "%d", numneighbors);
+ if (vertex) {
+ FOREACHneighbor_(vertex) {
+ if (neighbor->visitid && neighbor->visitid < numfacets)
+ fprintf (fp, " %d", neighbor->visitid);
+ }
+ }
+ fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
+ }else
+ fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
+ }else {
+ if (numinf)
+ numneighbors++;
+ fprintf (fp, "%d", numneighbors);
+ if (vertex) {
+ FOREACHneighbor_(vertex) {
+ if (neighbor->visitid == 0) {
+ if (numinf) {
+ numinf= 0;
+ fprintf (fp, " %d", neighbor->visitid);
+ }
+ }else if (neighbor->visitid < numfacets)
+ fprintf (fp, " %d", neighbor->visitid);
+ }
+ }
+ fprintf (fp, "\n");
+ }
+ }
+ if (format == qh_PRINTgeom)
+ fprintf (fp, "}\n");
+ qh_settempfree (&vertices);
+} /* printvoronoi */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvnorm">-</a>
+
+ 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
+
+ see:
+ qh_printvdiagram()
+ qh_eachvoronoi()
+*/
+void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+ pointT *normal;
+ realT offset;
+ int k;
+
+ normal= qh_detvnorm (vertex, vertexA, centers, &offset);
+ fprintf (fp, "%d %d %d ",
+ 2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
+ for (k= 0; k< qh hull_dim-1; k++)
+ fprintf (fp, qh_REAL_1, normal[k]);
+ fprintf (fp, qh_REAL_1, offset);
+ fprintf (fp, "\n");
+} /* printvnorm */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="printvridge">-</a>
+
+ 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
+*/
+void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+ facetT *facet, **facetp;
+
+ fprintf (fp, "%d %d %d", qh_setsize (centers)+2,
+ qh_pointid (vertex->point), qh_pointid (vertexA->point));
+ FOREACHfacet_(centers)
+ fprintf (fp, " %d", facet->visitid);
+ fprintf (fp, "\n");
+} /* printvridge */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="projectdim3">-</a>
+
+ 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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="readfeasible">-</a>
+
+ qh_readfeasible( dim, remainder )
+ read feasible point from remainder string 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, char *remainder) {
+ boolT isfirst= True;
+ int linecount= 0, tokcount= 0;
+ char *s, *t, firstline[qh_MAXfirst+1];
+ coordT *coords, value;
+
+ if (!qh HALFspace) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
+ if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
+ fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
+ qh_errexit(qh_ERRmem, NULL, NULL);
+ }
+ coords= qh feasible_point;
+ while ((s= (isfirst ? remainder : 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) {
+ fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
+ s);
+ qh_errexit (qh_ERRinput, NULL, NULL);
+ }
+ return linecount;
+ }
+ }
+ }
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="readpoints">-</a>
+
+ 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: this routine needs rewriting
+*/
+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, *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", 5) || !memcmp (firstline, "BEGIN", 5))
+ break;
+ else if (!*qh rbox_command)
+ strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+ }
+ if (!s) {
+ fprintf (qh ferr, "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", 5) || !memcmp (s, "BEGIN", 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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr,"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) {
+ fprintf(qh ferr,"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) {
+ fprintf(qh ferr,"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*) 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*)malloc ((qh maxline+1) * sizeof (char));
+ *ismalloc= True; /* use malloc since memory not setup */
+ coords= points= qh temp_malloc=
+ (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
+ if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
+ fprintf(qh ferr, "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", 3) || !memcmp (s, "END", 3)) {
+ if (qh CDDinput )
+ break;
+ else if (wasbegin)
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
+ if (wasbegin)
+ fprintf (qh ferr, "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) {
+ fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n",
+ linecount, (int) (s - qh line));
+ qh_errexit(qh_ERRinput, NULL, NULL);
+ }
+ isfirst= False;
+ }
+ if (tokcount != maxcount) {
+ newnum= fmin_(numinput, tokcount/diminput);
+ fprintf(qh ferr,"\
+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)
+ fprintf(qh ferr, ", line %d is the first comment", firsttext);
+ if (firstshort)
+ fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
+ if (firstlong)
+ fprintf(qh ferr, ", line %d is the first long line", firstlong);
+ fprintf(qh ferr, ". 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"))
+ fprintf (qh ferr, "\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@geom.umn.edu.\n\
+\n\
+Type 'qhull' for a short list of options.\n");
+ }
+ free (qh line);
+ qh line= NULL;
+ if (qh half_space) {
+ free (qh half_space);
+ qh half_space= NULL;
+ }
+ qh temp_malloc= NULL;
+ trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n",
+ numinput, diminput));
+ return(points);
+} /* readpoints */
+
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="setfeasible">-</a>
+
+ 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)) {
+ fprintf(qh ferr, "\
+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*)malloc (dim* sizeof(coordT)))) {
+ fprintf(qh ferr, "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) {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-io.htm#TOC"
+ >-------------------------------</a><a name="skipfacet">-</a>
+
+ 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 */
+
diff --git a/extern/qhull/src/io.h b/extern/qhull/src/io.h
new file mode 100755
index 00000000000..351d56b3708
--- /dev/null
+++ b/extern/qhull/src/io.h
@@ -0,0 +1,149 @@
+/*<html><pre> -<a href="qh-io.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ io.h
+ declarations of Input/Output functions
+
+ see README, qhull.h and io.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+/*============ constants and flags ==================*/
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_MAXfirst">-</a>
+
+ qh_MAXfirst
+ maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst 200
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_MINradius">-</a>
+
+ qh_MINradius
+ min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_GEOMepsilon">-</a>
+
+ qh_GEOMepsilon
+ adjust outer planes for 'lines closer' and geomview roundoff.
+ This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="qh_WHITESPACE">-</a>
+
+ qh_WHITESPACE
+ possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="RIDGE">-</a>
+
+ qh_RIDGE
+ to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+ qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*-<a href="qh-io.htm#TOC"
+ >--------------------------------</a><a name="printvridgeT">-</a>
+
+ printvridgeT
+ prints results of qh_printvdiagram
+
+ see:
+ <a href="io.c#printvridge">qh_printvridge</a> for an example
+*/
+typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+void dfacet( unsigned id);
+void dvertex( unsigned id);
+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_printafacet(FILE *fp, int format, facetT *facet, boolT printall);
+void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void qh_printcenter (FILE *fp, int format, char *string, facetT *facet);
+void qh_printcentrum (FILE *fp, facetT *facet, realT radius);
+void qh_printend (FILE *fp, int 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, int printall);
+void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void qh_printfacet(FILE *fp, facetT *facet);
+void qh_printfacet2math(FILE *fp, facetT *facet, 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, 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, int 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, int format);
+void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format);
+void qh_printfacetheader(FILE *fp, facetT *facet);
+void qh_printfacetridges(FILE *fp, facetT *facet);
+void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void qh_printhelp_degenerate(FILE *fp);
+void qh_printhelp_singular(FILE *fp);
+void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+ setT *vertices, realT color[3]);
+void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void qh_printpoint(FILE *fp, char *string, pointT *point);
+void qh_printpointid(FILE *fp, 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, int 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, int 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, char* string, facetT *facetlist,
+ setT *facets, boolT printall);
+void qh_printvertices (FILE *fp, char* string, setT *vertices);
+void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void qh_printvoronoi (FILE *fp, int 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_projectdim3 (pointT *source, pointT *destination);
+int qh_readfeasible (int dim, char *remainder);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+void qh_setfeasible (int dim);
+boolT qh_skipfacet(facetT *facet);
+
+#endif /* qhDEFio */
diff --git a/extern/qhull/src/mem.c b/extern/qhull/src/mem.c
new file mode 100755
index 00000000000..72934626684
--- /dev/null
+++ b/extern/qhull/src/mem.c
@@ -0,0 +1,447 @@
+/*<html><pre> -<a href="qh-mem.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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(sizeof(facetT));
+ qh_memsize(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-2002 The Geometry Center
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mem.h"
+
+#ifndef qhDEFqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void qh_errexit(int exitcode, facetT *, ridgeT *);
+#endif
+
+/*============ -global data structure ==============
+ see mem.h for definition
+*/
+
+qhmemT qhmem= {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 ======== */
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="intcompare">-</a>
+
+ qh_intcompare( i, j )
+ used by qsort and bsearch to compare two integers
+*/
+static int qh_intcompare(const void *i, const void *j) {
+ return(*((int *)i) - *((int *)j));
+} /* intcompare */
+
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="memalloc">-</a>
+
+ 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 malloc()
+*/
+void *qh_memalloc(int insize) {
+ void **freelistp, *newbuffer;
+ int index, size;
+ int outsize, bufsize;
+ void *object;
+
+ if ((unsigned) insize <= (unsigned) qhmem.LASTsize) {
+ index= qhmem.indextable[insize];
+ freelistp= qhmem.freelists+index;
+ if ((object= *freelistp)) {
+ qhmem.cntquick++;
+ *freelistp= *((void **)*freelistp); /* replace freelist with next object */
+ return (object);
+ }else {
+ outsize= qhmem.sizetable[index];
+ qhmem.cntshort++;
+ if (outsize > qhmem .freesize) {
+ if (!qhmem.curbuffer)
+ bufsize= qhmem.BUFinit;
+ else
+ bufsize= qhmem.BUFsize;
+ qhmem.totshort += bufsize;
+ if (!(newbuffer= malloc(bufsize))) {
+ fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+ 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;
+ }
+ object= qhmem.freemem;
+ qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
+ qhmem.freesize -= outsize;
+ return object;
+ }
+ }else { /* long allocation */
+ if (!qhmem.indextable) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
+ qh_errexit(qhmem_ERRqhull, NULL, NULL);
+ }
+ outsize= insize;
+ qhmem .cntlong++;
+ qhmem .curlong++;
+ qhmem .totlong += outsize;
+ if (qhmem.maxlong < qhmem.totlong)
+ qhmem.maxlong= qhmem.totlong;
+ if (!(object= malloc(outsize))) {
+ fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+ qh_errexit(qhmem_ERRmem, NULL, NULL);
+ }
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", outsize, object);
+ }
+ return (object);
+} /* memalloc */
+
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="memfree">-</a>
+
+ qh_memfree( object, size )
+ 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 free(object)
+*/
+void qh_memfree(void *object, int size) {
+ void **freelistp;
+
+ if (!object)
+ return;
+ if (size <= qhmem.LASTsize) {
+ qhmem .freeshort++;
+ freelistp= qhmem.freelists + qhmem.indextable[size];
+ *((void **)object)= *freelistp;
+ *freelistp= object;
+ }else {
+ qhmem .freelong++;
+ qhmem .totlong -= size;
+ free (object);
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
+ }
+} /* memfree */
+
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="memfreeshort">-</a>
+
+ qh_memfreeshort( curlong, totlong )
+ frees up all short and qhmem memory allocations
+
+ returns:
+ number and size of current long allocations
+*/
+void qh_memfreeshort (int *curlong, int *totlong) {
+ void *buffer, *nextbuffer;
+
+ *curlong= qhmem .cntlong - qhmem .freelong;
+ *totlong= qhmem .totlong;
+ for(buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
+ nextbuffer= *((void **) buffer);
+ free(buffer);
+ }
+ qhmem.curbuffer= NULL;
+ if (qhmem .LASTsize) {
+ free (qhmem .indextable);
+ free (qhmem .freelists);
+ free (qhmem .sizetable);
+ }
+ memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
+} /* memfreeshort */
+
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="meminit">-</a>
+
+ 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 */
+ qhmem.ferr= ferr;
+ if (sizeof(void*) < sizeof(int)) {
+ fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int). qset.c will not work\n");
+ exit (1); /* can not use qh_errexit() */
+ }
+} /* meminit */
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="meminitbuffers">-</a>
+
+ 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) {
+ fprintf (qhmem.ferr, "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 (numsizes, sizeof(int));
+ qhmem.freelists= (void **) calloc (numsizes, sizeof(void *));
+ if (!qhmem.sizetable || !qhmem.freelists) {
+ fprintf(qhmem.ferr, "qhull error (qh_meminit): insufficient memory\n");
+ qh_errexit (qhmem_ERRmem, NULL, NULL);
+ }
+ if (qhmem.IStracing >= 1)
+ fprintf (qhmem.ferr, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
+} /* meminitbuffers */
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="memsetup">-</a>
+
+ qh_memsetup()
+ set up memory after running memsize()
+*/
+void qh_memsetup (void) {
+ int k,i;
+
+ qsort(qhmem.sizetable, qhmem.TABLEsize, sizeof(int), qh_intcompare);
+ qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
+ if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) {
+ fprintf (qhmem.ferr, "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 *)malloc((qhmem.LASTsize+1) * sizeof(int)))) {
+ fprintf(qhmem.ferr, "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 */
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="memsize">-</a>
+
+ qh_memsize( size )
+ define a free list for this size
+*/
+void qh_memsize(int size) {
+ int k;
+
+ if (qhmem .LASTsize) {
+ fprintf (qhmem .ferr, "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
+ fprintf(qhmem.ferr, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
+} /* memsize */
+
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="memstatistics">-</a>
+
+ qh_memstatistics( fp )
+ print out memory statistics
+
+ notes:
+ does not account for wasted memory at the end of each block
+*/
+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;
+ }
+ fprintf (fp, "\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 long memory allocated (except for input)\n\
+%7d bytes of long memory in use (in %d pieces)\n\
+%7d bytes per memory buffer (initially %d bytes)\n",
+ qhmem .cntquick, qhmem.cntshort, qhmem.cntlong,
+ qhmem .freeshort, qhmem.freelong,
+ qhmem .totshort - qhmem .freesize - totfree,
+ totfree,
+ qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
+ qhmem .BUFsize, qhmem .BUFinit);
+ if (qhmem.cntlarger) {
+ fprintf (fp, "%7d calls to qh_setlarger\n%7.2g average copy size\n",
+ qhmem.cntlarger, ((float) qhmem.totlarger)/ qhmem.cntlarger);
+ fprintf (fp, " freelists (bytes->count):");
+ }
+ for (i=0; i < qhmem.TABLEsize; i++) {
+ count=0;
+ for (object= qhmem .freelists[i]; object; object= *((void **)object))
+ count++;
+ fprintf (fp, " %d->%d", qhmem.sizetable[i], count);
+ }
+ fprintf (fp, "\n\n");
+} /* memstatistics */
+
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="NOmem">-</a>
+
+ qh_NOmem
+ turn off quick-fit memory allocation
+
+ notes:
+ uses malloc() and free() instead
+*/
+#else /* qh_NOmem */
+
+void *qh_memalloc(int insize) {
+ void *object;
+
+ if (!(object= malloc(insize))) {
+ fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+ qh_errexit(qhmem_ERRmem, NULL, NULL);
+ }
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", insize, object);
+ return object;
+}
+
+void qh_memfree(void *object, int size) {
+
+ if (!object)
+ return;
+ free (object);
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
+}
+
+void qh_memfreeshort (int *curlong, int *totlong) {
+
+ memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
+ *curlong= 0;
+ *totlong= 0;
+}
+
+void qh_meminit (FILE *ferr) {
+
+ memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
+ qhmem.ferr= ferr;
+ if (sizeof(void*) < sizeof(int)) {
+ fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int). qset.c will not work\n");
+ 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) {
+
+}
+
+#endif /* qh_NOmem */
diff --git a/extern/qhull/src/mem.h b/extern/qhull/src/mem.h
new file mode 100755
index 00000000000..e9ebd1bb9bc
--- /dev/null
+++ b/extern/qhull/src/mem.h
@@ -0,0 +1,174 @@
+/*<html><pre> -<a href="qh-mem.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem
+
+/*-<a href="qh-mem.htm#TOC"
+ >-------------------------------</a><a name="NOmem">-</a>
+
+ 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@geom.umn.edu. If this can
+ not be done, define qh_NOmem to use malloc/free instead.
+
+ #define qh_NOmem
+*/
+
+/*-------------------------------------------
+ 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 <a href="user.h#MEMalign">qh_MEMalign</a> in user.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4 /* matches qh_ERRmem in qhull.h */
+#define qhmem_ERRqhull 5 /* matches qh_ERRqhull in qhull.h */
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="ptr_intT">-</a>
+
+ ptr_intT
+ for casting a void* to an integer-type
+
+ notes:
+ On 64-bit machines, a pointer may be larger than an 'int'.
+ qh_meminit() checks that 'long' holds a 'void*'
+*/
+typedef unsigned long ptr_intT;
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="qhmemT">-</a>
+
+ 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;
+
+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 free memory in bytes */
+ void *tempstack; /* stack of temporary memory, managed by users */
+ FILE *ferr; /* file for reporting errors */
+ int IStracing; /* =5 if tracing memory allocations */
+ int cntquick; /* count of quick allocations */
+ /* remove statistics doesn't effect speed */
+ int cntshort; /* count of short allocations */
+ int cntlong; /* count of long allocations */
+ int curlong; /* current count of inuse, long allocations */
+ int freeshort; /* count of short memfrees */
+ int freelong; /* count of long memfrees */
+ int totshort; /* total size of short allocations */
+ int totlong; /* total size of long allocations */
+ int maxlong; /* maximum totlong */
+ int cntlarger; /* count of setlarger's */
+ int totlarger; /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="memalloc_">-</a>
+
+ qh_memalloc_(size, object, type)
+ returns object of size bytes
+ assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#ifdef qh_NOmem
+#define qh_memalloc_(size, freelistp, object, type) {\
+ object= (type*)qh_memalloc (size); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(size, freelistp, object, type) {\
+ freelistp= qhmem.freelists + qhmem.indextable[size];\
+ if ((object= (type*)*freelistp)) {\
+ qhmem.cntquick++; \
+ *freelistp= *((void **)*freelistp);\
+ }else object= (type*)qh_memalloc (size);}
+#endif
+
+/*-<a href="qh-mem.htm#TOC"
+ >--------------------------------</a><a name="memfree_">-</a>
+
+ qh_memfree_(object, size)
+ free up an object
+
+ notes:
+ object may be NULL
+ assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+#ifdef qh_NOmem
+#define qh_memfree_(object, size, freelistp) {\
+ qh_memfree (object, size); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(object, size, freelistp) {\
+ if (object) { \
+ qhmem .freeshort++;\
+ freelistp= qhmem.freelists + qhmem.indextable[size];\
+ *((void **)object)= *freelistp;\
+ *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+void *qh_memalloc(int insize);
+void qh_memfree (void *object, int size);
+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);
+
+#endif /* qhDEFmem */
diff --git a/extern/qhull/src/merge.c b/extern/qhull/src/merge.c
new file mode 100755
index 00000000000..34ecda1865f
--- /dev/null
+++ b/extern/qhull/src/merge.c
@@ -0,0 +1,3626 @@
+/*<html><pre> -<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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 qhull.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-2002 The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+#ifndef qh_NOmerge
+
+/*=========== internal prototypes =========*/
+
+static int qh_compareangle(const void *p1, const void *p2);
+static int qh_comparemerge(const void *p1, const void *p2);
+static int qh_comparevisit (const void *p1, const void *p2);
+
+
+/*===== functions (alphabetical after premerge and postmerge) ======*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="premerge">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="postmerge">-</a>
+
+ 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 (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");
+ fprintf (qh ferr, "\n%s with 'C%.2g' and 'A%.2g'\n",
+ reason, maxcentrum, maxangle);
+ }
+ trace2((qh ferr, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="all_merges">-</a>
+
+ 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, "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, 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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="appendmergeset">-</a>
+
+ 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_(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) {
+ fprintf(qh ferr, "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)) {
+ fprintf(qh ferr, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="basevertices">-</a>
+
+ 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, "qh_basevertices: found %d vertices\n",
+ qh_setsize (vertices)));
+ return vertices;
+} /* basevertices */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="checkconnect">-</a>
+
+ 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;
+ fprintf(qh ferr, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="checkzero">-</a>
+
+ 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, "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, "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, "qh_checkzero: facet f%d needs pre-merging\n",
+ facet->id));
+ return False;
+
+ LABELnonconvex:
+ trace2((qh ferr, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="compareangle">-</a>
+
+ qh_compareangle( angle1, angle2 )
+ used by qsort() to order merges by angle
+*/
+static int qh_compareangle(const void *p1, const void *p2) {
+ mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
+
+ return ((a->angle > b->angle) ? 1 : -1);
+} /* compareangle */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="comparemerge">-</a>
+
+ qh_comparemerge( merge1, merge2 )
+ used by qsort() to order merges
+*/
+static int qh_comparemerge(const void *p1, const void *p2) {
+ mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
+
+ return (a->type - b->type);
+} /* comparemerge */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="comparevisit">-</a>
+
+ qh_comparevisit( vertex1, vertex2 )
+ used by qsort() to order vertices by their visitid
+*/
+static int qh_comparevisit (const void *p1, const void *p2) {
+ vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
+
+ return (a->visitid - b->visitid);
+} /* comparevisit */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="copynonconvex">-</a>
+
+ 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, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",
+ atridge->id, ridge->id));
+ break;
+ }
+ }
+} /* copynonconvex */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="degen_redundant_facet">-</a>
+
+ 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, "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, "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, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
+ }
+} /* degen_redundant_facet */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="degen_redundant_neighbors">-</a>
+
+ 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, "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, "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, "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, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors. Neighbor of f%d.\n", neighbor->id, size, facet->id));
+ }
+ }
+} /* degen_redundant_neighbors */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="find_newvertex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "qh_find_newvertex: find new vertex for v%d from ",
+ oldvertex->id);
+ FOREACHvertex_(vertices)
+ fprintf (qh ferr, "v%d ", vertex->id);
+ FOREACHridge_(ridges)
+ fprintf (qh ferr, "r%d ", ridge->id);
+ fprintf (qh ferr, "\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 += qh_setsize (ridges);
+ if (!qh_setsize (vertices)) {
+ trace4((qh ferr, "qh_find_newvertex: vertices not in ridges for v%d\n",
+ oldvertex->id));
+ return NULL;
+ }
+ qsort (SETaddr_(vertices, vertexT), 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, "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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="findbest_test">-</a>
+
+ 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
+ maxdist= dist;
+ }else
+ dist= qh_getdistance (facet, neighbor, &mindist, &maxdist);
+ if (dist < *distp) {
+ *bestfacet= neighbor;
+ *mindistp= mindist;
+ *maxdistp= maxdist;
+ *distp= dist;
+ }
+} /* findbest_test */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="findbestneighbor">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="flippedmerges">-</a>
+
+ 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, "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, "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, sizeof(mergeT));
+ else
+ qh_setappend (&qh facet_mergeset, merge);
+ }
+ qh_settempfree (&othermerges);
+ if (nummerge)
+ *wasmerge= True;
+ trace1((qh ferr, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
+} /* flippedmerges */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="forcedmerges">-</a>
+
+ 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, "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)) {
+ fprintf (qh ferr, "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, "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, sizeof(mergeT));
+ else
+ qh_setappend (&qh facet_mergeset, merge);
+ }
+ qh_settempfree (&othermerges);
+ if (nummerge)
+ *wasmerge= True;
+ trace1((qh ferr, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n",
+ nummerge, numflip));
+} /* forcedmerges */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="getmergeset">-</a>
+
+ 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, "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), nummerges,sizeof(mergeT *),qh_compareangle);
+ else
+ qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
+ if (qh POSTmerging) {
+ zadd_(Zmergesettot2, nummerges);
+ }else {
+ zadd_(Zmergesettot, nummerges);
+ zmax_(Zmergesetmax, nummerges);
+ }
+ trace2((qh ferr, "qh_getmergeset: %d merges found\n", nummerges));
+} /* getmergeset */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="getmergeset_initial">-</a>
+
+ 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), nummerges,sizeof(mergeT *),qh_compareangle);
+ else
+ qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
+ if (qh POSTmerging) {
+ zadd_(Zmergeinittot2, nummerges);
+ }else {
+ zadd_(Zmergeinittot, nummerges);
+ zmax_(Zmergeinitmax, nummerges);
+ }
+ trace2((qh ferr, "qh_getmergeset_initial: %d merges found\n", nummerges));
+} /* getmergeset_initial */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="hashridge">-</a>
+
+ 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= (int)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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="hashridge_find">-</a>
+
+ 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= (int)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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="makeridges">-</a>
+
+ 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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mark_dupridges">-</a>
+
+ 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, "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, "qh_mark_dupridges: found %d duplicated ridges\n",
+ nummerge));
+} /* mark_dupridges */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="maydropneighbor">-</a>
+
+ 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, "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, "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, "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, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
+ }
+} /* maydropneighbor */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="merge_degenredundant">-</a>
+
+ 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, 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) {
+ fprintf (qh ferr, "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, "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, "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, "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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="merge_nonconvex">-</a>
+
+ 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, "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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergecycle">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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, "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;
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, " same cycle:");
+ FORALLsame_cycle_(samecycle)
+ fprintf(qh ferr, " f%d", same->id);
+ fprintf (qh ferr, "\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) {
+ fprintf (qh ferr, "qh_mergecycle: end of trace facet\n");
+ qh IStracing= tracerestore;
+ }
+} /* mergecycle */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergecycle_all">-</a>
+
+ 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, "qh_mergecycle_all: begin\n"));
+ for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
+ if (facet->normal)
+ continue;
+ if (!facet->mergehorizon) {
+ fprintf (qh ferr, "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= nummerge;
+ zzinc_(Zcyclehorizon);
+ total += facets;
+ zzadd_(Zcyclefacettot, facets);
+ zmax_(Zcyclefacetmax, facets);
+ }
+ cycles++;
+ }
+ if (cycles)
+ *wasmerge= True;
+ trace1((qh ferr, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));
+} /* mergecycle_all */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergecycle_facets">-</a>
+
+ 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, "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, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
+ samecycle->id, newfacet->id));
+} /* mergecycle_facets */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergecycle_neighbors">-</a>
+
+ 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, "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, "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, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
+ delneighbors, newneighbors));
+} /* mergecycle_neighbors */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergecycle_ridges">-</a>
+
+ 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, "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, "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 {
+ fprintf (qh ferr, "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, sizeof(ridgeT), freelistp);
+ numold++;
+ }else if (neighbor->visitid == samevisitid) {
+ qh_setdel (neighbor->ridges, ridge);
+ qh_setfree(&(ridge->vertices));
+ qh_memfree_(ridge, 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, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
+ numold, numnew));
+} /* mergecycle_ridges */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergecycle_vneighbors">-</a>
+
+ 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, "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, "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, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
+ samecycle->id, newfacet->id));
+} /* mergecycle_vneighbors */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergefacet">-</a>
+
+ 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
+ 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) {
+ fprintf (qh ferr, "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;
+ fprintf (qh ferr, "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;
+ fprintf (qh ferr, "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;
+ }
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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) {
+ fprintf(qh ferr, "\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)
+ fprintf(qh ferr, "Option 'Qx' may avoid this problem.\n");
+ qh_errexit(qh_ERRinput, 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= 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) {
+ fprintf (qh ferr, "qh_mergefacet: end of wide tracing\n");
+ qh IStracing= tracerestore;
+ }
+} /* mergefacet */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergefacet2d">-</a>
+
+ 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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergeneighbors">-</a>
+
+ 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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergeridges">-</a>
+
+ 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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergesimplex">-</a>
+
+ 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, "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, "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, "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, 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, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",
+ facet1->id, getid_(apex), facet2->id));
+} /* mergesimplex */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergevertex_del">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergevertex_neighbors">-</a>
+
+ 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, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
+ facet1->id, facet2->id));
+ if (qh tracevertex) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="mergevertices">-</a>
+
+ 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)) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="neighbor_intersections">-</a>
+
+ 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, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
+ qh_setsize (intersect), vertex->id));
+ return intersect;
+} /* neighbor_intersections */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="newvertices">-</a>
+
+ 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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="reducevertices">-</a>
+
+ 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, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
+ numshare, numrename, degenredun));
+ return degenredun;
+} /* reducevertices */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="redundant_vertex">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="remove_extravertices">-</a>
+
+ 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, "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, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
+ }else
+ trace3((qh ferr, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="rename_sharedvertex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="renameridgevertex">-</a>
+
+ 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, "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, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="renamevertex">-</a>
+
+ 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)
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="test_appendmerge">-</a>
+
+ 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, "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, "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, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="test_vneighbors">-</a>
+
+ 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, "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, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
+ nummerges));
+ return (nummerges > 0);
+} /* test_vneighbors */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="tracemerge">-</a>
+
+ 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)) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="tracemerging">-</a>
+
+ 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);
+ fprintf (qh ferr, "\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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="updatetested">-</a>
+
+ 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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="vertexridges">-</a>
+
+ 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, "qh_vertexridges: found %d ridges for v%d\n",
+ size, vertex->id));
+ }
+ return ridges;
+} /* vertexridges */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="vertexridges_facet">-</a>
+
+ 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 */
+
+/*-<a href="qh-merge.htm#TOC"
+ >-------------------------------</a><a name="willdelete">-</a>
+
+ 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 (char *reason, realT maxcentrum, realT maxangle,
+ boolT vneighbors) {
+}
+boolT qh_checkzero (boolT testall) {
+ }
+#endif /* qh_NOmerge */
+
diff --git a/extern/qhull/src/merge.h b/extern/qhull/src/merge.h
new file mode 100755
index 00000000000..7fc2afa5967
--- /dev/null
+++ b/extern/qhull/src/merge.h
@@ -0,0 +1,171 @@
+/*<html><pre> -<a href="qh-merge.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ merge.h
+ header file for merge.c
+
+ see qh-merge.htm and merge.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+
+/*============ -constants- ==============*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_ANGLEredundant">-</a>
+
+ qh_ANGLEredundant
+ indicates redundant merge in mergeT->angle
+*/
+#define qh_ANGLEredundant 6.0
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_ANGLEdegen">-</a>
+
+ qh_ANGLEdegen
+ indicates degenerate facet in mergeT->angle
+*/
+#define qh_ANGLEdegen 5.0
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_ANGLEconcave">-</a>
+
+ 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
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="MRG">-</a>
+
+ 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 (not enough neighbors) facet1 == facet2 */
+ MRGredundant, /* redundant facet (vertex subset) */
+ /* merge_degenredundant assumes degen < redundant */
+ MRGmirror, /* mirror facet from qh_triangulate */
+ ENDmrg
+} mergeType;
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="qh_MERGEapex">-</a>
+
+ qh_MERGEapex
+ flag for qh_mergefacet() to indicate an apex merge
+*/
+#define qh_MERGEapex True
+
+/*============ -structures- ====================*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="mergeT">-</a>
+
+ 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- =========================*/
+
+/*-<a href="qh-merge.htm#TOC"
+ >--------------------------------</a><a name="FOREACHmerge_">-</a>
+
+ 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 <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#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 (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);
+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/extern/qhull/src/poly.c b/extern/qhull/src/poly.c
new file mode 100755
index 00000000000..6319e43d66a
--- /dev/null
+++ b/extern/qhull/src/poly.c
@@ -0,0 +1,1180 @@
+/*<html><pre> -<a href="qh-poly.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ poly.c
+ implements polygons and simplices
+
+ see qh-poly.htm, poly.h and qhull.h
+
+ infrequent code is in poly2.c
+ (all but top 50 and their callers 12/3/95)
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="appendfacet">-</a>
+
+ 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, "qh_appendfacet: append f%d to facet_list\n", facet->id));
+} /* appendfacet */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="appendvertex">-</a>
+
+ 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, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));
+} /* appendvertex */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="attachnewfacets">-</a>
+
+ 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 ) {
+ facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
+ ridgeT *ridge, **ridgep;
+
+ qh NEWfacets= True;
+ trace3((qh ferr, "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, sizeof(ridgeT));
+ }
+ }
+ SETfirst_(visible->ridges)= NULL;
+ }
+ SETfirst_(visible->neighbors)= NULL;
+ }
+ trace1((qh ferr, "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 {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="checkflipped">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="delfacet">-</a>
+
+ 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, "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, sizeof(facetT), freelistp);
+} /* delfacet */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="deletevisible">-</a>
+
+ 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, "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) {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="facetintersect">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
+ facetA->id, *skipA, facetB->id, *skipB));
+ return(intersect);
+} /* facetintersect */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="gethash">-</a>
+
+ qh_gethash( hashsize, set, size, firstindex, skipelem )
+ return hashvalue for a set with firstindex and skipelem
+
+ notes:
+ 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
+*/
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem) {
+ void **elemp= SETelemaddr_(set, firstindex, void);
+ ptr_intT hash = 0, elem;
+ int i;
+
+ 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;
+ }
+ hash %= (ptr_intT) hashsize;
+ /* hash= 0; for debugging purposes */
+ return hash;
+} /* gethash */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="makenewfacet">-</a>
+
+ 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= toporient;
+ if (horizon)
+ qh_setappend(&(newfacet->neighbors), horizon);
+ qh_appendfacet(newfacet);
+ return(newfacet);
+} /* makenewfacet */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="makenewplanes">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="makenew_nonsimplicial">-</a>
+
+ 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, 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) {
+ fprintf (qh ferr, "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, sizeof(ridgeT));
+ }else {
+ qh_setappend(&(newfacet->ridges), ridge);
+ if (toporient)
+ ridge->top= newfacet;
+ else
+ ridge->bottom= newfacet;
+ }
+ trace4((qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="makenew_simplicial">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="matchneighbor">-</a>
+
+ 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= (int)qh_gethash (hashsize, newfacet->vertices, qh hull_dim, 1,
+ SETelem_(newfacet->vertices, newskip));
+ trace4((qh ferr, "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");
+ fprintf (qh ferr, "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 == (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, "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");
+ fprintf (qh ferr, "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, "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, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
+ newfacet->id, newskip, hash));
+} /* matchneighbor */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="matchnewfacets">-</a>
+
+ 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, "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; newskip<qh hull_dim; newskip++) /* furthest/horizon already matched */
+ qh_matchneighbor (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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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++;
+ }
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="matchvertices">-</a>
+
+ 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);
+ *same= !(((ptr_intT)skipA & 0x1) ^ ((ptr_intT)*skipB & 0x1));
+ trace4((qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="newfacet">-</a>
+
+ 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_(sizeof(facetT), freelistp, facet, facetT);
+ memset ((char *)facet, 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, "qh_newfacet: created facet f%d\n", facet->id));
+ return (facet);
+} /* newfacet */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="newridge">-</a>
+
+ qh_newridge()
+ return a new ridge
+*/
+ridgeT *qh_newridge(void) {
+ ridgeT *ridge;
+ void **freelistp; /* used !qh_NOmem */
+
+ qh_memalloc_(sizeof(ridgeT), freelistp, ridge, ridgeT);
+ memset ((char *)ridge, 0, sizeof(ridgeT));
+ zinc_(Ztotridges);
+ if (qh ridge_id == 0xFFFFFF) {
+ fprintf(qh ferr, "\
+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, "qh_newridge: created ridge r%d\n", ridge->id));
+ return (ridge);
+} /* newridge */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="pointid">-</a>
+
+ 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:
+ if point not in point array
+ the code does a comparison of unrelated pointers.
+*/
+int qh_pointid (pointT *point) {
+ long offset, id;
+
+ if (!point)
+ id= -3;
+ else if (point == qh interior_point)
+ id= -2;
+ else if (point >= qh first_point
+ && point < qh first_point + qh num_points * qh hull_dim) {
+ offset= point - qh first_point;
+ id= offset / qh hull_dim;
+ }else if ((id= qh_setindex (qh other_points, point)) != -1)
+ id += qh num_points;
+ else
+ id= -1;
+ return (int) id;
+} /* pointid */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="removefacet">-</a>
+
+ 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, "qh_removefacet: remove f%d from facet_list\n", facet->id));
+} /* removefacet */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="removevertex">-</a>
+
+ 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, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));
+} /* removevertex */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="updatevertices">-</a>
+
+ 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, "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, "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, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n",
+ qh_pointid(vertex->point), vertex->id, visible->id));
+ }
+ }
+ }
+ }
+} /* updatevertices */
+
+
+
diff --git a/extern/qhull/src/poly.h b/extern/qhull/src/poly.h
new file mode 100755
index 00000000000..294ec9527fc
--- /dev/null
+++ b/extern/qhull/src/poly.h
@@ -0,0 +1,290 @@
+/*<html><pre> -<a href="qh-poly.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ poly.h
+ header file for poly.c and poly2.c
+
+ see qh-poly.htm, qhull.h and poly.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+/*=============== constants ========================== */
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="ALGORITHMfault">-</a>
+
+ ALGORITHMfault
+ use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="DATAfault">-</a>
+
+ DATAfault
+ use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="DUPLICATEridge">-</a>
+
+ 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
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="MERGEridge">-</a>
+
+ 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- =========================*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLfacet_">-</a>
+
+ 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 )
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLnew_facets">-</a>
+
+ 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 )
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLvertex_">-</a>
+
+ 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 )
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLvisible_facets">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLsame_">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLsame_cycle_">-</a>
+
+ 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))
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHneighborA_">-</a>
+
+ 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:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHneighborA_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvisible_">-</a>
+
+ FOREACHvisible_( facets ) { ... }
+ assign 'visible' to each facet in facets
+
+ notes:
+ uses 'facetT *facet, *facetp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHnewfacet_">-</a>
+
+ FOREACHnewfacet_( facets ) { ... }
+ assign 'newfacet' to each facet in facets
+
+ notes:
+ uses 'facetT *newfacet, *newfacetp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertexA_">-</a>
+
+ FOREACHvertexA_( vertices ) { ... }
+ assign 'vertexA' to each vertex in vertices
+
+ notes:
+ uses 'vertexT *vertexA, *vertexAp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertexreverse12_">-</a>
+
+ FOREACHvertexreverse12_( vertices ) { ... }
+ assign 'vertex' to each vertex in vertices
+ reverse order of first two vertices
+
+ notes:
+ uses 'vertexT *vertex, *vertexp;'
+ see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#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);
+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);
+unsigned 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, unsigned 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_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/extern/qhull/src/poly2.c b/extern/qhull/src/poly2.c
new file mode 100755
index 00000000000..713faab8bed
--- /dev/null
+++ b/extern/qhull/src/poly2.c
@@ -0,0 +1,3070 @@
+/*<html><pre> -<a href="qh-poly.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ poly2.c
+ implements polygons and simplices
+
+ see qh-poly.htm, poly.h and qhull.h
+
+ frequently used code is in poly.c
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="addhash">-</a>
+
+ 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, unsigned 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="check_bestdist">-</a>
+
+ 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, "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, "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)
+ fprintf (qh ferr, "\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;
+ fprintf(qh ferr, "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)
+ fprintf(qh ferr, "\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) {
+ fprintf( qh ferr, "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, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
+} /* check_bestdist */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="check_maxout">-</a>
+
+ 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, "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, "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)
+ fprintf (qh ferr, "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;
+ zinc_(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))
+ fprintf (qh ferr, "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, "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
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="check_output">-</a>
+
+ 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 */
+
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="check_point">-</a>
+
+ 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;
+ }
+ fprintf(qh ferr, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="check_points">-</a>
+
+ 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, "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 * qh num_points;
+ else
+ total= (float) qh num_facets * qh num_points;
+ if (total >= qh_VERIFYdirect && !qh maxoutdone) {
+ if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING)
+ fprintf (qh ferr, "\n\
+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)
+ fprintf (qh ferr, "\n\
+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)
+ fprintf (qh ferr, "\n\
+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)
+ fprintf (qh ferr, "\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
+ fprintf (qh ferr, "\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) {
+ fprintf( qh ferr, "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) {
+ fprintf( qh ferr, "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, "qh_check_points: max distance outside %2.2g\n", maxdist));
+ }
+} /* check_points */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="checkconvex">-</a>
+
+ 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, "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");
+ fprintf (qh ferr, "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");
+ fprintf (qh ferr, "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");
+ fprintf (qh ferr, "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");
+ fprintf (qh ferr, "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, "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;
+ fprintf (qh ferr, "qhull note: 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");
+ fprintf (qh ferr, "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");
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="checkfacet">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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)) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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)) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="checkflipped_all">-</a>
+
+ 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)) {
+ fprintf(qh ferr, "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) {
+ fprintf (qh ferr, "\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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="checkpolygon">-</a>
+
+ 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, "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
+ ) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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 += numfacets;
+ if (facetlist == qh facet_list) {
+ if (numfacets != qh num_facets - qh num_visible) {
+ fprintf(qh ferr, "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) {
+ fprintf(qh ferr, "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)) {
+ fprintf(qh ferr, "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) {
+ fprintf (qh ferr, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
+ numvertices, numfacets);
+ waserror= True;
+ }
+ if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="checkvertex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
+ waserror= True;
+ }
+ if (vertex->id >= qh vertex_id) {
+ fprintf (qh ferr, "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)) {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="clearcenters">-</a>
+
+ 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 (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, "qh_clearcenters: switched to center type %d\n", type));
+} /* clearcenters */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="createsimplex">-</a>
+
+ 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= 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, "qh_createsimplex: created simplex\n"));
+} /* createsimplex */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="delridge">-</a>
+
+ 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, sizeof(ridgeT), freelistp);
+} /* delridge */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="delvertex">-</a>
+
+ 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, sizeof(vertexT));
+} /* delvertex */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="facet3vertex">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="findbestfacet">-</a>
+
+ 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:
+ this works for all distributions
+ 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:
+ <a href="geom.c#findbest">qh_findbest</a>
+*/
+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, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
+ bestfacet->id, *bestdist, *isoutside, totpart));
+ return bestfacet;
+} /* findbestfacet */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="findfacet_all">-</a>
+
+ 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
+*/
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+ int *numpart) {
+ facetT *bestfacet= NULL, *facet;
+ realT dist;
+ int totpart= 0;
+
+ *bestdist= REALmin;
+ *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, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",
+ getid_(bestfacet), *bestdist, *isoutside, totpart));
+ return bestfacet;
+} /* findfacet_all */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="findgood">-</a>
+
+ 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, "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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="findgood_all">-</a>
+
+ 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) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "qhull warning: point p%d is not a vertex ('QV%d').\n",
+ qh GOODvertex-1, qh GOODvertex-1);
+ else
+ fprintf (qh ferr, "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, "qh_findgood_all: f%d is closest (%2.2g) to thresholds\n",
+ bestfacet->id, bestangle));
+ return;
+ }
+ }
+ qh num_good= numgood;
+ trace0((qh ferr, "qh_findgood_all: %d good facets remain out of %d facets\n",
+ numgood, startgood));
+} /* findgood_all */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="furthestnext">-</a>
+
+ 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, "qh_furthestnext: made f%d next facet (dist %.2g)\n",
+ bestfacet->id, bestdist));
+ }
+} /* furthestnext */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="furthestout">-</a>
+
+ 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, "qh_furthestout: p%d is furthest outside point of f%d\n",
+ qh_pointid (point), facet->id));
+} /* furthestout */
+
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="infiniteloop">-</a>
+
+ qh_infiniteloop( facet )
+ report infinite loop error due to facet
+*/
+void qh_infiniteloop (facetT *facet) {
+
+ fprintf (qh ferr, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");
+ qh_errexit (qh_ERRqhull, facet, NULL);
+} /* qh_infiniteloop */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="initbuild">-</a>
+
+ 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)))) {
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "\nTrace level %d for %s | %s\n",
+ qh IStracing ? qh IStracing : qh TRACElevel, qh rbox_command, qh qhull_command);
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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))) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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, "qh_initbuild: initial hull created and points partitioned\n"));
+} /* initbuild */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="initialhull">-</a>
+
+ 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 ^= True;
+ }
+ FORALLfacets
+ qh_setfacetplane(facet);
+ FORALLfacets {
+ if (!qh_checkflipped (facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
+ trace1((qh ferr, "qh_initialhull: initial orientation incorrect. Correct all facets\n"));
+ facet->flipped= False;
+ FORALLfacets {
+ facet->toporient ^= True;
+ qh_orientoutside (facet);
+ }
+ break;
+ }
+ }
+ FORALLfacets {
+ if (!qh_checkflipped (facet, NULL, !qh_ALL)) { /* can happen with 'R0.1' */
+ qh_precision ("initial facet is coplanar with interior point");
+ fprintf (qh ferr, "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)
+ fprintf (qh ferr, "qhull precision warning: \n\
+The initial hull is narrow (cosine of min. angle is %.16f).\n\
+A coplanar point may lead to a wide facet. Options 'QbB' (scale to unit box)\n\
+or 'Qbb' (scale last coordinate) may remove this warning. Use 'Pp' to skip\n\
+this warning. See 'Limitations' in qh-impre.htm.\n",
+ -minangle); /* convert from angle between normals to angle between facets */
+ }
+ 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) {
+ fprintf(qh ferr, "qh_initialhull: simplex constructed, interior point:");
+ for (k=0; k < qh hull_dim; k++)
+ fprintf (qh ferr, " %6.4g", qh interior_point[k]);
+ fprintf (qh ferr, "\n");
+ }
+#endif
+} /* initialhull */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="initialvertices">-</a>
+
+ 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 index, 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);
+ index= (int)floor(qh num_points * randr);
+ while (qh_setin (simplex, qh_point (index))) {
+ index++; /* in case qh_RANDOMint always returns the same value */
+ index= index < qh num_points ? index : 0;
+ }
+ qh_setappend (&simplex, qh_point (index));
+ }
+ }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++;
+ }
+ }
+ }
+ index= 0;
+ while (k != dim && (point= qh_point (index++))) {
+ 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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="isvertex">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="makenewfacets">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="matchduplicates">-</a>
+
+ 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= (int)qh_gethash (hashsize, atfacet->vertices, qh hull_dim, 1,
+ SETelem_(atfacet->vertices, atskip));
+ trace2((qh ferr, "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 == (newfacet->toporient ^ facet->toporient));
+ if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
+ if (!makematch) {
+ fprintf (qh ferr, "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, "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, "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) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="nearcoplanar">-</a>
+
+ qh_nearcoplanar()
+ for all facets, remove near-inside points from facet->coplanarset</li>
+ 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 (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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="nearvertex">-</a>
+
+ 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) {
+ fprintf(qh ferr, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
+ qh_errexit(qh_ERRqhull, NULL, NULL);
+ }
+ vertices= qh_settemp (qh TEMPsize);
+ apex= SETfirst_(facet->vertices);
+ 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);
+ return bestvertex;
+} /* nearvertex */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="newhashtable">-</a>
+
+ 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 ((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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="newvertex">-</a>
+
+ qh_newvertex( point )
+ returns a new vertex for point
+*/
+vertexT *qh_newvertex(pointT *point) {
+ vertexT *vertex;
+
+ zinc_(Ztotvertices);
+ vertex= (vertexT *)qh_memalloc(sizeof(vertexT));
+ memset ((char *) vertex, 0, sizeof (vertexT));
+ if (qh vertex_id == 0xFFFFFF) {
+ fprintf(qh ferr, "qhull input error: more than %d vertices. ID field overflows and two vertices\n\
+may have the same identifier. Vertices not sorted correctly.\n", 0xFFFFFF);
+ qh_errexit(qh_ERRinput, NULL, NULL);
+ }
+ if (qh vertex_id == qh tracevertex_id)
+ qh tracevertex= vertex;
+ vertex->id= qh vertex_id++;
+ vertex->point= point;
+ trace4((qh ferr, "qh_newvertex: vertex p%d (v%d) created\n", qh_pointid(vertex->point),
+ vertex->id));
+ return (vertex);
+} /* newvertex */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="nextridge3d">-</a>
+
+ qh_nextridge3d( atridge, facet, vertex )
+ return next ridge and vertex for a 3d facet
+
+ notes:
+ in qh_ORIENTclock order
+ this is a O(n^2) implementation to trace all ridges
+ be sure to stop on any 2nd visit
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="outcoplanar">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="point">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="point_add">-</a>
+
+ 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)
+ fprintf (qh ferr, "qhull internal warning (point_add): unknown point %p id %d\n",
+ point, id);
+ else if (id >= size) {
+ fprintf (qh ferr, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="pointfacet">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="pointvertex">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="prependfacet">-</a>
+
+ 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, "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 */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="printhashtable">-</a>
+
+ 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;
+ fprintf (fp, "hash %d f%d ", facet_i, facet->id);
+ FOREACHvertex_(facet->vertices)
+ fprintf (fp, "v%d ", vertex->id);
+ fprintf (fp, "\n neighbors:");
+ FOREACHneighbor_i_(facet) {
+ if (neighbor == qh_MERGEridge)
+ id= -3;
+ else if (neighbor == qh_DUPLICATEridge)
+ id= -2;
+ else
+ id= getid_(neighbor);
+ fprintf (fp, " %d", id);
+ }
+ fprintf (fp, "\n");
+ }
+ }
+} /* printhashtable */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="printlists">-</a>
+
+ 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;
+
+ fprintf (qh ferr, "qh_printlists: facets:");
+ FORALLfacets {
+ if (++count % 100 == 0)
+ fprintf (qh ferr, "\n ");
+ fprintf (qh ferr, " %d", facet->id);
+ }
+ fprintf (qh ferr, "\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)
+ fprintf (qh ferr, "\n ");
+ fprintf (qh ferr, " %d", vertex->id);
+ }
+ fprintf (qh ferr, "\n");
+} /* printlists */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="resetlists">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="setvoronoi_all">-</a>
+
+ 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
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="triangulate">-</a>
+
+ qh_triangulate()
+ triangulate non-simplicial facets on qh.facet_list,
+ if qh.CENTERtype=qh_ASvoronoi, sets Voronoi centers of non-simplicial facets
+
+ 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;
+
+ trace1((qh ferr, "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, "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) {
+ fprintf( qh ferr, "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, "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, sizeof(mergeT));
+ if (mergetype == MRGmirror) {
+ zinc_(Ztrimirror);
+ qh_triangulate_mirror (facet1, facet2);
+ }
+ }
+ qh_settempfree(&qh degen_mergeset);
+ trace2((qh ferr, "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, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));
+ trace2((qh ferr, "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, "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, "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) {
+ fprintf( qh ferr, "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, "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);
+} /* triangulate */
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="triangulate_facet">-</a>
+
+ 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, "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= SETfirst_(facetA->vertices);
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="triangulate_link">-</a>
+
+ 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, "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) {
+ fprintf( qh ferr, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="triangulate_mirror">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="triangulate_null">-</a>
+
+ 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, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
+ neighbor= SETfirst_(facetA->neighbors);
+ otherfacet= SETsecond_(facetA->neighbors);
+ qh_triangulate_link (facetA, neighbor, facetA, otherfacet);
+ qh_willdelete (facetA, NULL);
+} /* triangulate_null */
+
+#else /* qh_NOmerge */
+void qh_triangulate (void) {
+}
+#endif /* qh_NOmerge */
+
+ /*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="vertexintersect">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="vertexintersect_new">-</a>
+
+ 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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="vertexneighbors">-</a>
+
+ 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, "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 */
+
+/*-<a href="qh-poly.htm#TOC"
+ >-------------------------------</a><a name="vertexsubset">-</a>
+
+ 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/extern/qhull/src/qconvex.c b/extern/qhull/src/qconvex.c
new file mode 100755
index 00000000000..67b78646e50
--- /dev/null
+++ b/extern/qhull/src/qconvex.c
@@ -0,0 +1,334 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qconvex.c
+ compute convex hulls using qhull
+
+ see unix.c for full interface
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <console.h>
+#include <Desk.h>
+
+#elif __cplusplus
+extern "C" {
+ int isatty (int);
+}
+
+#elif _MSC_VER
+#include <io.h>
+#define isatty _isatty
+
+#else
+int isatty (int); /* returns 1 if stdin is a tty
+ if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt">-</a>
+
+ qh_prompt
+ long prompt for qconvex
+
+ notes:
+ restricted version of qhull.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.geom.umn.edu/software/qhull %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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt2">-</a>
+
+ 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 - 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt3">-</a>
+
+ 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\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\
+";
+
+/*-<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="main">-</a>
+
+ 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/extern/qhull/src/qdelaun.c b/extern/qhull/src/qdelaun.c
new file mode 100755
index 00000000000..0e49d9c381e
--- /dev/null
+++ b/extern/qhull/src/qdelaun.c
@@ -0,0 +1,323 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qdelaun.c
+ compute Delaunay triangulations and furthest-point Delaunay
+ triangulations using qhull
+
+ see unix.c for full interface
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <console.h>
+#include <Desk.h>
+
+#elif __cplusplus
+extern "C" {
+ int isatty (int);
+}
+
+#elif _MSC_VER
+#include <io.h>
+#define isatty _isatty
+
+#else
+int isatty (int); /* returns 1 if stdin is a tty
+ if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt">-</a>
+
+ qh_prompt
+ long prompt for qhull
+
+ notes:
+ restricted version of qhull.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.geom.umn.edu/software/qhull %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\
+ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt2">-</a>
+
+ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt3">-</a>
+
+ 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\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\
+";
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="main">-</a>
+
+ 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/extern/qhull/src/qhalf.c b/extern/qhull/src/qhalf.c
new file mode 100755
index 00000000000..a2b3875dd7f
--- /dev/null
+++ b/extern/qhull/src/qhalf.c
@@ -0,0 +1,324 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qhalf.c
+ compute the intersection of halfspaces about a point
+
+ see unix.c for full interface
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <console.h>
+#include <Desk.h>
+
+#elif __cplusplus
+extern "C" {
+ int isatty (int);
+}
+
+#elif _MSC_VER
+#include <io.h>
+#define isatty _isatty
+
+#else
+int isatty (int); /* returns 1 if stdin is a tty
+ if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt">-</a>
+
+ qh_prompt
+ long prompt for qhull
+
+ notes:
+ restricted version of qhull.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.geom.umn.edu/software/qhull %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\
+ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt2">-</a>
+
+ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt3">-</a>
+
+ 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 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\
+";
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="main">-</a>
+
+ 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/extern/qhull/src/qhull.c b/extern/qhull/src/qhull.c
new file mode 100755
index 00000000000..dc835bb4f28
--- /dev/null
+++ b/extern/qhull/src/qhull.c
@@ -0,0 +1,1395 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qhull.c
+ Quickhull algorithm for convex hulls
+
+ qhull() and top-level routines
+
+ see qh-qhull.htm, qhull.h, unix.c
+
+ see qhull_a.h for internal functions
+
+ copyright (c) 1993-2002 The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*============= functions in alphabetic order after qhull() =======*/
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="qhull">-</a>
+
+ 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, "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 (/*visible_list, newfacet_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);
+ fprintf (qh ferr, "\nTesting all coplanar points.\n");
+ }
+ qh_check_maxout();
+ }
+ if (qh KEEPnearinside && !qh maxoutdone)
+ qh_nearcoplanar();
+ }
+ if (qh_setsize ((setT*)qhmem.tempstack) != 0) {
+ fprintf (qh ferr, "qhull internal error (qh_qhull): temporary sets not empty (%d)\n",
+ qh_setsize ((setT*)qhmem.tempstack));
+ qh_errexit (qh_ERRqhull, NULL, NULL);
+ }
+ qh hulltime= qh_CPUclock - qh hulltime;
+ qh QHULLfinished= True;
+ trace1((qh ferr, "qh_qhull: algorithm completed\n"));
+} /* qhull */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="addpoint">-</a>
+
+ 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:
+ check point in qh.first_point/.num_points
+ 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) {
+ fprintf (qh ferr, "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 (/*visible_list, newfacet_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, "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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="build_withrestart">-</a>
+
+ 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);
+ qh ERREXITcalled= False;
+ qh STOPcone= True; /* if break, prevents normal output */
+ }
+ if (!qh RERUN && qh JOGGLEmax < REALmax/2) {
+ if (qh build_cnt > qh_JOGGLEmaxretry) {
+ fprintf(qh ferr, "\n\
+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= False;
+ qh_freebuild (True); /* first call is a nop */
+ qh build_cnt++;
+ if (!qh qhull_optionsiz)
+ qh qhull_optionsiz= strlen (qh qhull_options);
+ else {
+ qh qhull_options [qh qhull_optionsiz]= '\0';
+ qh qhull_optionlen= 80;
+ }
+ 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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="buildhull">-</a>
+
+ 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, "qh_buildhull: start build hull\n"));
+ FORALLfacets {
+ if (facet->visible || facet->newfacet) {
+ fprintf (qh ferr, "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) {
+ fprintf (qh ferr, "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,"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) {
+ fprintf (qh ferr, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside);
+ qh_errexit (qh_ERRqhull, NULL, NULL);
+ }
+ trace1((qh ferr, "qh_buildhull: completed the hull construction\n"));
+} /* buildhull */
+
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="buildtracing">-</a>
+
+ 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= qh_CPUclock - qh hulltime;
+ cpu /= qh_SECticks;
+ total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+ fprintf (qh ferr, "\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= qh_CPUclock - qh hulltime;
+ cpu /= qh_SECticks;
+ total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+ zinc_(Zdistio);
+ qh_distplane (furthest, facet, &dist);
+ fprintf (qh ferr, "\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= qh_CPUclock - qh hulltime;
+ cpu /= qh_SECticks;
+ qh_distplane (furthest, facet, &dist);
+ fprintf (qh ferr, "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);
+ }
+ if (qh visit_id > (unsigned) INT_MAX) {
+ qh visit_id= 0;
+ FORALLfacets
+ facet->visitid= qh visit_id;
+ }
+ if (qh vertex_visit > (unsigned) INT_MAX) {
+ qh vertex_visit= 0;
+ FORALLvertices
+ vertex->visitid= qh vertex_visit;
+ }
+ qh furthest_id= furthestid;
+ qh RANDOMdist= qh old_randomdist;
+} /* buildtracing */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="errexit2">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="findhorizon">-</a>
+
+ 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,"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) {
+ fprintf (qh ferr, "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, "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");
+ fprintf(qh ferr, "qhull precision error (qh_findhorizon): empty horizon\n\
+Point 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, "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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="nextfurthest">-</a>
+
+ 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, index;
+ 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);
+ index= (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 > index) {
+ *visible= facet;
+ return ((pointT*)qh_setdelnth (facet->outsideset, index));
+ }else
+ index -= size;
+ }
+ }
+ fprintf (qh ferr, "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, index+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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="partitionall">-</a>
+
+ qh_partitionall( vertices, points, numpoints )
+ partitions all points in points/numpoints to the outsidesets of facets
+ vertices= vertices in qh.facet_list (not 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, "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 */
+
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="partitioncoplanar">-</a>
+
+ 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, 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, "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, "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, "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) {
+ fprintf (qh ferr, "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, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
+ qh_pointid(point), bestfacet->id, bestdist));
+} /* partitioncoplanar */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="partitionpoint">-</a>
+
+ 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, "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, "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, "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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="partitionvisible">-</a>
+
+ 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 (not 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(/*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) {
+ fprintf (qh ferr, "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,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
+} /* partitionvisible */
+
+
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="precision">-</a>
+
+ qh_precision( reason )
+ restart on precision errors if not merging and if 'QJn'
+*/
+void qh_precision (char *reason) {
+
+ if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) {
+ if (qh JOGGLEmax < REALmax/2) {
+ trace0((qh ferr, "qh_precision: qhull restart because of %s\n", reason));
+ longjmp(qh restartexit, qh_ERRprec);
+ }
+ }
+} /* qh_precision */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="printsummary">-</a>
+
+ 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;
+ 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)
+ fprintf (fp, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error.");
+ 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)
+ fprintf (fp, "\n\
+Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+ else
+ fprintf (fp, "\n\
+Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+ fprintf(fp, " Number of Voronoi regions%s: %d\n",
+ qh ATinfinity ? " and at-infinity" : "", numvertices);
+ if (numdel)
+ fprintf(fp, " Total number of deleted points due to merging: %d\n", numdel);
+ if (numcoplanars - numdel > 0)
+ fprintf(fp, " Number of nearly incident points: %d\n", numcoplanars - numdel);
+ else if (size - numvertices - numdel > 0)
+ fprintf(fp, " Total number of nearly incident points: %d\n", size - numvertices - numdel);
+ fprintf(fp, " Number of%s Voronoi vertices: %d\n",
+ goodused ? " 'good'" : "", qh num_good);
+ if (nonsimplicial)
+ fprintf(fp, " Number of%s non-simplicial Voronoi vertices: %d\n",
+ goodused ? " 'good'" : "", nonsimplicial);
+ }else if (qh DELAUNAY) {
+ if (qh UPPERdelaunay)
+ fprintf (fp, "\n\
+Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+ else
+ fprintf (fp, "\n\
+Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+ fprintf(fp, " Number of input sites%s: %d\n",
+ qh ATinfinity ? " and at-infinity" : "", numvertices);
+ if (numdel)
+ fprintf(fp, " Total number of deleted points due to merging: %d\n", numdel);
+ if (numcoplanars - numdel > 0)
+ fprintf(fp, " Number of nearly incident points: %d\n", numcoplanars - numdel);
+ else if (size - numvertices - numdel > 0)
+ fprintf(fp, " Total number of nearly incident points: %d\n", size - numvertices - numdel);
+ fprintf(fp, " Number of%s Delaunay regions: %d\n",
+ goodused ? " 'good'" : "", qh num_good);
+ if (nonsimplicial)
+ fprintf(fp, " Number of%s non-simplicial Delaunay regions: %d\n",
+ goodused ? " 'good'" : "", nonsimplicial);
+ }else if (qh HALFspace) {
+ fprintf (fp, "\n\
+Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+ fprintf(fp, " Number of halfspaces: %d\n", size);
+ fprintf(fp, " 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";
+ fprintf(fp, " Number of %s halfspaces: %d\n", s, numcoplanars);
+ }
+ fprintf(fp, " Number of intersection points: %d\n", qh num_facets - qh num_visible);
+ if (goodused)
+ fprintf(fp, " Number of 'good' intersection points: %d\n", qh num_good);
+ if (nonsimplicial)
+ fprintf(fp, " Number of%s non-simplicial intersection points: %d\n",
+ goodused ? " 'good'" : "", nonsimplicial);
+ }else {
+ fprintf (fp, "\n\
+Convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+ fprintf(fp, " 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";
+ fprintf(fp, " Number of %s points: %d\n", s, numcoplanars);
+ }
+ fprintf(fp, " Number of facets: %d\n", qh num_facets - qh num_visible);
+ if (goodused)
+ fprintf(fp, " Number of 'good' facets: %d\n", qh num_good);
+ if (nonsimplicial)
+ fprintf(fp, " Number of%s non-simplicial facets: %d\n",
+ goodused ? " 'good'" : "", nonsimplicial);
+ }
+ if (numtricoplanars)
+ fprintf(fp, " Number of triangulated facets: %d\n", numtricoplanars);
+ fprintf(fp, "\nStatistics for: %s | %s",
+ qh rbox_command, qh qhull_command);
+ if (qh ROTATErandom != INT_MIN)
+ fprintf(fp, " QR%d\n\n", qh ROTATErandom);
+ else
+ fprintf(fp, "\n\n");
+ fprintf(fp, " Number of points processed: %d\n", zzval_(Zprocessed));
+ fprintf(fp, " Number of hyperplanes created: %d\n", zzval_(Zsetplane));
+ if (qh DELAUNAY)
+ fprintf(fp, " Number of facets in hull: %d\n", qh num_facets - qh num_visible);
+ fprintf(fp, " 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;
+ fprintf(fp, " average new facet balance: %2.2g\n",
+ wval_(Wnewbalance)/zval_(Zprocessed));
+ stddev= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance),
+ wval_(Wnewbalance2), &ave);
+ fprintf(fp, " new facet standard deviation: %2.2g\n", stddev);
+ fprintf(fp, " average partition balance: %2.2g\n",
+ wval_(Wpbalance)/zval_(Zpbalance));
+ stddev= qh_stddev (zval_(Zpbalance), wval_(Wpbalance),
+ wval_(Wpbalance2), &ave);
+ fprintf(fp, " partition standard deviation: %2.2g\n", stddev);
+ }
+#endif
+ if (nummerged) {
+ fprintf(fp," Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
+ zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+
+ zzval_(Zdistzero));
+ fprintf(fp," Number of distance tests for checking: %d\n",zzval_(Zcheckpart));
+ fprintf(fp," Number of merged facets: %d\n", nummerged);
+ }
+ if (!qh RANDOMoutside && qh QHULLfinished) {
+ cpu= qh hulltime;
+ cpu /= qh_SECticks;
+ wval_(Wcpu)= cpu;
+ fprintf (fp, " CPU seconds to compute hull (after input): %2.4g\n", cpu);
+ }
+ if (qh RERUN) {
+ if (!qh PREmerge && !qh MERGEexact)
+ fprintf(fp, " 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))
+ fprintf(fp, " After %d retries, input joggled by: %2.2g\n",
+ zzval_(Zretry), qh JOGGLEmax);
+ else
+ fprintf(fp, " Input joggled by: %2.2g\n", qh JOGGLEmax);
+ }
+ if (qh totarea != 0.0)
+ fprintf(fp, " %s facet area: %2.8g\n",
+ zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea);
+ if (qh totvol != 0.0)
+ fprintf(fp, " %s volume: %2.8g\n",
+ zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol);
+ if (qh MERGING) {
+ qh_outerinner (NULL, &outerplane, &innerplane);
+ if (outerplane > 2 * qh DISTround) {
+ fprintf(fp, " 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)
+ fprintf (fp, " (%.1fx)\n", ratio);
+ else
+ fprintf (fp, "\n");
+ }
+ if (innerplane < -2 * qh DISTround) {
+ fprintf(fp, " 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)
+ fprintf (fp, " (%.1fx)\n", ratio);
+ else
+ fprintf (fp, "\n");
+ }
+ }
+ fprintf(fp, "\n");
+} /* printsummary */
+
+
diff --git a/extern/qhull/src/qhull.h b/extern/qhull/src/qhull.h
new file mode 100755
index 00000000000..896ec1e9c18
--- /dev/null
+++ b/extern/qhull/src/qhull.h
@@ -0,0 +1,1048 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qhull.h
+ user-level header file for using qhull.a library
+
+ see qh-qhull.htm, qhull_a.h
+
+ copyright (c) 1993-2002, The Geometry Center
+
+ 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 qhull.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 qhull.h
+
+ recompile qhull if you change this file
+*/
+
+#ifndef qhDEFqhull
+#define qhDEFqhull 1
+
+/*=========================== -included files ==============*/
+
+#include <setjmp.h>
+#include <float.h>
+#include <time.h>
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <Desk.h>
+#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 qhull.h
+#endif
+#endif
+#endif
+
+#include "user.h" /* user defineable constants */
+
+/*============ constants and basic types ====================*/
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_VERSION">-</a>
+
+ qh_VERSION
+ version string by year and date
+
+ the revision increases on code changes only
+
+ notes:
+ change date: Changes.txt, Announce.txt, README.txt, qhull.man
+ qhull-news.html, Eudora signatures,
+ change version: README.txt, qhull.html, file_id.diz, Makefile
+ change year: Copying.txt
+ check download size
+ recompile user_eg.c, rbox.c, qhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c
+ make copy of qhull-news.html as qh-news.htm
+*/
+
+#define qh_VERSION "2002.1 2002/8/20"
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="coordT">-</a>
+
+ coordT
+ coordinates and coefficients are stored as realT (i.e., double)
+
+ notes:
+ 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
+
+/*-<a href="qh-geom.htm#TOC"
+ >--------------------------------</a><a name="pointT">-</a>
+
+ pointT
+ a point is an array of DIM3 coordinates
+*/
+#define pointT coordT
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="flagT">-</a>
+
+ flagT
+ Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="boolT">-</a>
+
+ boolT
+ boolean value, either True or False
+
+ notes:
+ needed for portability
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="CENTERtype">-</a>
+
+ qh_CENTER
+ to distinguish facet->center
+*/
+typedef enum
+{
+ qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
+}
+qh_CENTER;
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_PRINT">-</a>
+
+ qh_PRINT
+ output formats for printing (qh.PRINTout).
+ 'Fa' 'FV' 'Fc' 'FC'
+
+
+ notes:
+ some of these names are similar to qh 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, /* 'n' 'Fo' 'i' 'm' '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;
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_ALL">-</a>
+
+ 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 */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="qh_ERR">-</a>
+
+ qh_ERR
+ Qhull exit codes, for indicating errors
+*/
+#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 */
+
+/* ============ -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
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="facetT">-</a>
+
+ 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 defines ridge */
+ 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) */
+};
+
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="ridgeT">-</a>
+
+ ridgeT
+ defines a ridge
+
+ notes:
+ a ridge is DIM3-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 */
+ 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 */
+};
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="vertexT">-</a>
+
+ 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; /* for use with qh vertex_visit */
+ unsigned id:24; /* unique identifier, =>room for 8 flags */
+ flagT seen:1; /* used to perform operations only once */
+ flagT seen2:1; /* another seen flag */
+ 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 ============================*/
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh">-</a>
+
+ qh
+ all global variables for qhull are in qh, qhmem, and qhstat
+
+ notes:
+ qhmem is defined in mem.h and qhstat is defined in stat.h
+ access to qh_qh is via the "qh" macro. See qh_QHpointer in user.h
+*/
+typedef struct qhT qhT;
+#if qh_QHpointer
+#define qh qh_qh->
+extern qhT *qh_qh; /* allocated in global.c */
+#else
+#define qh qh_qh.
+extern qhT qh_qh;
+#endif
+
+struct qhT {
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-const">-</a>
+
+ 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 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 */
+ 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 (not 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 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 */
+ 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 before qh_initbuild */
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-prec">-</a>
+
+ 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 */
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-intern">-</a>
+
+ qh internal constants
+ internal constants for Qhull
+*/
+ char qhull[sizeof("qhull")]; /* for checking ownership */
+ void *old_stat; /* pointer to saved qh_qhstat, qh_save_qhull */
+ 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) */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-lists">-</a>
+
+ 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; /* ID of next, new ridge from newridge() */
+ unsigned vertex_id; /* ID of next, new vertex from newvertex() */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-var">-</a>
+
+ 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 */
+ 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 */
+ realT totvol; /* 'FA': total volume computed by qh_getarea */
+ unsigned int visit_id; /* unique ID for searching neighborhoods, */
+ unsigned int vertex_visit; /* unique ID for searching vertices */
+ boolT ZEROall_ok; /* True if qh_checkzero always succeeds */
+ boolT WAScoplanar; /* True if qh_partitioncoplanar (qh_check_maxout) */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-set">-</a>
+
+ 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 (first is qh interior_point) */
+ setT *del_vertices; /* vertices to partition and delete with visible
+ facets. Have deleted set for checkfacet */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-buf">-</a>
+
+ 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 */
+
+/*-<a href="qh-globa.htm#TOC"
+ >--------------------------------</a><a name="qh-static">-</a>
+
+ 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 errexit (prevents duplicate calls */
+ boolT firstcentrum; /* for qh_printcentrum */
+ 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 */
+ boolT old_randomdist; /* save RANDOMdist when io, tracing, or statistics */
+ int ridgeoutnum; /* number of ridges in 4OFF output */
+ void *old_qhstat; /* for saving qh_qhstat in save_qhull() */
+ setT *old_tempstack; /* for saving qhmem.tempstack in save_qhull */
+ setT *coplanarset; /* set of coplanar facets for searching qh_findbesthorizon() */
+};
+
+/*=========== -macros- =========================*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="otherfacet_">-</a>
+
+ otherfacet_(ridge, facet)
+ return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+ (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="getid_">-</a>
+
+ getid_(p)
+ return ID for facet, ridge, or vertex
+ return MAXINT if NULL (-1 causes type conversion error )
+*/
+#define getid_(p) ((p) ? (p)->id : -1)
+
+/*============== FORALL macros ===================*/
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLfacets">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLpoints">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLpoint_">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FORALLvertices">-</a>
+
+ 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)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHfacet_">-</a>
+
+ FOREACHfacet_( facets ) { ... }
+ assign 'facet' to each facet in facets
+
+ declare:
+ facetT *facet, **facetp;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHfacet_(facets) FOREACHsetelement_(facetT, facets, facet)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHneighbor_">-</a>
+
+ 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:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHneighbor_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHpoint_">-</a>
+
+ FOREACHpoint_( points ) { ... }
+ assign 'point' to each point in points set
+
+ declare:
+ pointT *point, **pointp;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHpoint_(points) FOREACHsetelement_(pointT, points, point)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHridge_">-</a>
+
+ FOREACHridge_( ridges ) { ... }
+ assign 'ridge' to each ridge in ridges set
+
+ declare:
+ ridgeT *ridge, **ridgep;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHridge_(ridges) FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertex_">-</a>
+
+ FOREACHvertex_( vertices ) { ... }
+ assign 'vertex' to each vertex in vertices set
+
+ declare:
+ vertexT *vertex, **vertexp;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHfacet_i_">-</a>
+
+ FOREACHfacet_i_( facets ) { ... }
+ assign 'facet' and 'facet_i' for each facet in facets set
+
+ declare:
+ facetT *facet;
+ int facet_n, facet_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHfacet_i_(facets) FOREACHsetelement_i_(facetT, facets, facet)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHneighbor_i_">-</a>
+
+ 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:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHneighbor_i_(facet) FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHpoint_i_">-</a>
+
+ FOREACHpoint_i_( points ) { ... }
+ assign 'point' and 'point_i' for each point in points set
+
+ declare:
+ pointT *point;
+ int point_n, point_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHpoint_i_(points) FOREACHsetelement_i_(pointT, points, point)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHridge_i_">-</a>
+
+ FOREACHridge_i_( ridges ) { ... }
+ assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+ declare:
+ ridgeT *ridge;
+ int ridge_n, ridge_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+*/
+#define FOREACHridge_i_(ridges) FOREACHsetelement_i_(ridgeT, ridges, ridge)
+
+/*-<a href="qh-poly.htm#TOC"
+ >--------------------------------</a><a name="FOREACHvertex_i_">-</a>
+
+ FOREACHvertex_i_( vertices ) { ... }
+ assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+ declare:
+ vertexT *vertex;
+ int vertex_n, vertex_i;
+
+ see:
+ <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a>
+ */
+#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
+
+/********* -qhull.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(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_user_memsizes (void);
+
+/***** -geom.c/geom2.c prototypes (duplicated from geom.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_freebuffers (void);
+void qh_freeqhull (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_start (FILE *infile, FILE *outfile, FILE *errfile);
+void qh_initthresholds (char *command);
+void qh_option (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 dfacet( unsigned id);
+void dvertex( unsigned id);
+void qh_printneighborhood (FILE *fp, int 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*/);
+
+/********* -stat.c prototypes (duplicated from stat.h) **********************/
+
+void qh_collectstatistics (void);
+void qh_printallstatistics (FILE *fp, char *string);
+
+#endif /* qhDEFqhull */
diff --git a/extern/qhull/src/qhull_a.h b/extern/qhull/src/qhull_a.h
new file mode 100755
index 00000000000..d4e69b071be
--- /dev/null
+++ b/extern/qhull/src/qhull_a.h
@@ -0,0 +1,127 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qhull_a.h
+ all header files for compiling qhull
+
+ see qh-qhull.htm
+
+ see qhull.h for user-level definitions
+
+ see user.h for user-defineable constants
+
+ defines internal functions for qhull.c global.c
+
+ copyright (c) 1993-2002, The Geometry Center
+
+ 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <math.h>
+#include <float.h> /* some compilers will not need float.h */
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+/*** uncomment here and qset.c
+ if string.h does not define memcpy()
+#include <memory.h>
+*/
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+#include "geom.h"
+#include "merge.h"
+#include "poly.h"
+#include "io.h"
+#include "stat.h"
+
+#if qh_CLOCKtype == 2 /* defined in user.h from qhull.h */
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+#endif
+
+#ifdef _MSC_VER /* Microsoft Visual C++ */
+#pragma warning( disable : 4056) /* float constant expression. Looks like a compiler bug */
+#pragma warning( disable : 4146) /* unary minus applied to unsigned type */
+#pragma warning( disable : 4244) /* conversion from 'unsigned long' to 'real' */
+#pragma warning( disable : 4305) /* conversion from 'const double' to 'float' */
+#endif
+
+/* ======= -macros- =========== */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >--------------------------------</a><a name="traceN">-</a>
+
+ traceN((fp.ferr, "format\n", vars));
+ calls fprintf if qh.IStracing >= N
+
+ notes:
+ removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh IStracing) fprintf args;}
+#define trace1(args) {if (qh IStracing >= 1) fprintf args;}
+#define trace2(args) {if (qh IStracing >= 2) fprintf args;}
+#define trace3(args) {if (qh IStracing >= 3) fprintf args;}
+#define trace4(args) {if (qh IStracing >= 4) fprintf args;}
+#define trace5(args) {if (qh IStracing >= 5) 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 */
+
+/***** -qhull.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 (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);
+int qh_strtol (const char *s, char **endp);
+double qh_strtod (const char *s, char **endp);
+
+/***** -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/extern/qhull/src/qhull_interface.cpp b/extern/qhull/src/qhull_interface.cpp
new file mode 100755
index 00000000000..6ecc640e82b
--- /dev/null
+++ b/extern/qhull/src/qhull_interface.cpp
@@ -0,0 +1,96 @@
+/*<html><pre> -<a href="qh-user.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+*/
+
+#include <iostream.h>
+#include <conio.h>
+
+//--- Include qhull, so it works from with in a C++ source file
+//---
+//--- In MVC one cannot just do:
+//---
+//--- extern "C"
+//--- {
+//--- #include "qhull_a.h"
+//--- }
+//---
+//--- Because qhull_a.h includes math.h, which can not appear
+//--- inside a extern "C" declaration.
+//---
+//--- Maybe that why Numerical recipes in C avoid this problem, by removing
+//--- standard include headers from its header files and add them in the
+//--- respective source files instead.
+//---
+//--- [K. Erleben]
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <qhull/qhull.h>
+#include <qhull/mem.h>
+#include <qhull/qset.h>
+#include <qhull/geom.h>
+#include <qhull/merge.h>
+#include <qhull/poly.h>
+#include <qhull/io.h>
+#include <qhull/stat.h>
+#if defined(__cplusplus)
+}
+#endif
+
+/*********************************************************************/
+/* */
+/* */
+/* */
+/* */
+/*********************************************************************/
+
+void compute_convex_hull(void)
+{
+ int dim; /* dimension of points */
+ int numpoints; /* number of points */
+ coordT *points; /* array of coordinates for each point */
+ boolT ismalloc; /* True if qhull should free points in qh_freeqhull() or reallocation */
+ char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
+ FILE *outfile= stdout; /* output from qh_produce_output()
+ use NULL to skip qh_produce_output() */
+ FILE *errfile= stderr; /* error messages from qhull code */
+ int exitcode; /* 0 if no error from qhull */
+ facetT *facet; /* set by FORALLfacets */
+ int curlong, totlong; /* memory remaining after qh_memfreeshort */
+
+ /* initialize dim, numpoints, points[], ismalloc here */
+ exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ if (!exitcode) { /* if no error */
+ /* 'qh facet_list' contains the convex hull */
+ FORALLfacets {
+ /* ... your code ... */
+ }
+ }
+ qh_freeqhull(!qh_ALL);
+ qh_memfreeshort (&curlong, &totlong);
+ if (curlong || totlong)
+ fprintf (errfile, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+ totlong, curlong);
+};
+
+/*********************************************************************/
+/* */
+/* */
+/* */
+/* */
+/*********************************************************************/
+
+void main()
+{
+ cout << "Hello world" << endl;
+
+ cout << "Press any key..." << endl;
+
+ while(!_kbhit());
+
+};
diff --git a/extern/qhull/src/qset.c b/extern/qhull/src/qset.c
new file mode 100755
index 00000000000..9e78464c07e
--- /dev/null
+++ b/extern/qhull/src/qset.c
@@ -0,0 +1,1301 @@
+/*<html><pre> -<a href="qh-set.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qset.c
+ implements set manipulations needed for quickhull
+
+ see qh-set.htm and qset.h
+
+ copyright (c) 1993-2002 The Geometry Center
+*/
+
+#include <stdio.h>
+#include <string.h>
+/*** uncomment here and qhull_a.h
+ if string.h does not define memcpy()
+#include <memory.h>
+*/
+#include "qset.h"
+#include "mem.h"
+
+#ifndef qhDEFqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void qh_errexit(int exitcode, facetT *, ridgeT *);
+#endif
+
+/*=============== internal macros ===========================*/
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="SETsizeaddr_">-</a>
+
+ SETsizeaddr_(set)
+ return pointer to actual size+1 of set (set CANNOT be NULL!!)
+
+ notes:
+ *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
+*/
+#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize].i))
+
+/*============ functions in alphabetical order ===================*/
+
+/*-<a href="qh-set.htm#TOC"
+ >--------------------------------<a name="setaddnth">-</a>
+
+ 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 *sizep, oldsize, i;
+ void **oldp, **newp;
+
+ if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+ qh_setlarger(setp);
+ sizep= SETsizeaddr_(*setp);
+ }
+ oldsize= *sizep - 1;
+ if (nth < 0 || nth > oldsize) {
+ fprintf (qhmem.ferr, "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)++;
+ oldp= SETelemaddr_(*setp, oldsize, void); /* NULL */
+ newp= oldp+1;
+ for (i= oldsize-nth+1; i--; ) /* move at least NULL */
+ *(newp--)= *(oldp--); /* may overwrite *sizep */
+ *newp= newelem;
+} /* setaddnth */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >--------------------------------<a name="setaddsorted">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setappend">-</a>
+
+ 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) {
+ int *sizep;
+ void **endp;
+
+ if (!newelem)
+ return;
+ if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+ qh_setlarger(setp);
+ sizep= SETsizeaddr_(*setp);
+ }
+ *(endp= &((*setp)->e[(*sizep)++ - 1].p))= newelem;
+ *(++endp)= NULL;
+} /* setappend */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setappend_set">-</a>
+
+ 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 *sizep, sizeA, size;
+ setT *oldset;
+
+ if (!setA)
+ return;
+ SETreturnsize_(setA, sizeA);
+ if (!*setp)
+ *setp= qh_setnew (sizeA);
+ sizep= SETsizeaddr_(*setp);
+ if (!(size= *sizep))
+ size= (*setp)->maxsize;
+ else
+ size--;
+ if (size + sizeA > (*setp)->maxsize) {
+ oldset= *setp;
+ *setp= qh_setcopy (oldset, sizeA);
+ qh_setfree (&oldset);
+ sizep= SETsizeaddr_(*setp);
+ }
+ *sizep= size+sizeA+1; /* memcpy may overwrite */
+ if (sizeA > 0)
+ memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), SETelemsize *(sizeA+1));
+} /* setappend_set */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setappend2ndlast">-</a>
+
+ 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) {
+ int *sizep;
+ void **endp, **lastp;
+
+ if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+ qh_setlarger(setp);
+ sizep= SETsizeaddr_(*setp);
+ }
+ endp= SETelemaddr_(*setp, (*sizep)++ -1, void); /* NULL */
+ lastp= endp-1;
+ *(endp++)= *lastp;
+ *endp= NULL; /* may overwrite *sizep */
+ *lastp= newelem;
+} /* setappend2ndlast */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setcheck">-</a>
+
+ 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, char *tname, int id) {
+ int maxsize, size;
+ int waserr= 0;
+
+ if (!set)
+ return;
+ SETreturnsize_(set, size);
+ maxsize= set->maxsize;
+ if (size > maxsize || !maxsize) {
+ fprintf (qhmem.ferr, "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) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_setcheck): %s%d (size %d max %d) is not null terminated.\n",
+ tname, id, maxsize, size-1);
+ waserr= 1;
+ }
+ if (waserr) {
+ qh_setprint (qhmem.ferr, "ERRONEOUS", set);
+ qh_errexit (qhmem_ERRqhull, NULL, NULL);
+ }
+} /* setcheck */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setcompact">-</a>
+
+ 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, destp-firstp);
+} /* setcompact */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setcopy">-</a>
+
+ 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)= size+1; /* memcpy may overwrite */
+ memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), SETelemsize *(size+1));
+ return (newset);
+} /* setcopy */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setdel">-</a>
+
+ 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) {
+ void **elemp, **lastp;
+ int *sizep;
+
+ if (!set)
+ return NULL;
+ elemp= SETaddr_(set, void);
+ while (*elemp != oldelem && *elemp)
+ elemp++;
+ if (*elemp) {
+ sizep= SETsizeaddr_(set);
+ if (!(*sizep)--) /* if was a full set */
+ *sizep= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
+ lastp= SETelemaddr_(set, *sizep-1, void);
+ *elemp= *lastp; /* may overwrite itself */
+ *lastp= NULL;
+ return oldelem;
+ }
+ return NULL;
+} /* setdel */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setdellast">-</a>
+
+ 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;
+ int *sizep;
+ void *returnvalue;
+
+ if (!set || !(set->e[0].p))
+ return NULL;
+ sizep= SETsizeaddr_(set);
+ if ((setsize= *sizep)) {
+ returnvalue= set->e[setsize - 2].p;
+ set->e[setsize - 2].p= NULL;
+ (*sizep)--;
+ }else {
+ maxsize= set->maxsize;
+ returnvalue= set->e[maxsize - 1].p;
+ set->e[maxsize - 1].p= NULL;
+ *sizep= maxsize;
+ }
+ return returnvalue;
+} /* setdellast */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setdelnth">-</a>
+
+ 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 **elemp, **lastp, *elem;
+ int *sizep;
+
+
+ elemp= SETelemaddr_(set, nth, void);
+ sizep= SETsizeaddr_(set);
+ if (!(*sizep)--) /* if was a full set */
+ *sizep= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
+ if (nth < 0 || nth >= *sizep) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+ qh_setprint (qhmem.ferr, "", set);
+ qh_errexit (qhmem_ERRqhull, NULL, NULL);
+ }
+ lastp= SETelemaddr_(set, *sizep-1, void);
+ elem= *elemp;
+ *elemp= *lastp; /* may overwrite itself */
+ *lastp= NULL;
+ return elem;
+} /* setdelnth */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setdelnthsorted">-</a>
+
+ 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 **newp, **oldp, *elem;
+ int *sizep;
+
+ sizep= SETsizeaddr_(set);
+ if (nth < 0 || (*sizep && nth >= *sizep-1) || nth >= set->maxsize) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+ qh_setprint (qhmem.ferr, "", set);
+ qh_errexit (qhmem_ERRqhull, NULL, NULL);
+ }
+ newp= SETelemaddr_(set, nth, void);
+ elem= *newp;
+ oldp= newp+1;
+ while ((*(newp++)= *(oldp++)))
+ ; /* copy remaining elements and NULL */
+ if (!(*sizep)--) /* if was a full set */
+ *sizep= set->maxsize; /* *sizep= (max size-1)+ 1 */
+ return elem;
+} /* setdelnthsorted */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setdelsorted">-</a>
+
+ 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) {
+ void **newp, **oldp;
+ int *sizep;
+
+ if (!set)
+ return NULL;
+ newp= SETaddr_(set, void);
+ while(*newp != oldelem && *newp)
+ newp++;
+ if (*newp) {
+ oldp= newp+1;
+ while ((*(newp++)= *(oldp++)))
+ ; /* copy remaining elements */
+ sizep= SETsizeaddr_(set);
+ if (!(*sizep)--) /* if was a full set */
+ *sizep= set->maxsize; /* *sizep= (max size-1)+ 1 */
+ return oldelem;
+ }
+ return NULL;
+} /* setdelsorted */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setduplicate">-</a>
+
+ 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, elemsize);
+ qh_setappend (&newSet, newElem);
+ }
+ return newSet;
+} /* setduplicate */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setequal">-</a>
+
+ qh_setequal( )
+ 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, sizeB;
+
+ SETreturnsize_(setA, sizeA);
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setequal_except">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setequal_skip">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setfree">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setfree2">-</a>
+
+ 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 */
+
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setfreelong">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setin">-</a>
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setindex">-</a>
+
+ 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.
+
+ design:
+ checks maxsize
+ scans set for atelem
+*/
+int qh_setindex(setT *set, void *atelem) {
+ void **elem;
+ int size, i;
+
+ 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setlarger">-</a>
+
+ 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, *sizep;
+ setT *newset, *set, **setp, *oldset;
+ void **oldp, **newp;
+
+ if (*oldsetp) {
+ oldset= *oldsetp;
+ SETreturnsize_(oldset, size);
+ qhmem.cntlarger++;
+ qhmem.totlarger += size+1;
+ newset= qh_setnew(2 * size);
+ oldp= SETaddr_(oldset, void);
+ newp= SETaddr_(newset, void);
+ memcpy((char *)newp, (char *)oldp, (size+1) * SETelemsize);
+ sizep= SETsizeaddr_(newset);
+ *sizep= size+1;
+ FOREACHset_((setT *)qhmem.tempstack) {
+ if (set == oldset)
+ *(setp-1)= newset;
+ }
+ qh_setfree(oldsetp);
+ }else
+ newset= qh_setnew(3);
+ *oldsetp= newset;
+} /* setlarger */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setlast">-</a>
+
+ qh_setlast( )
+ 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);
+ if (!size)
+ return SETelem_(set, set->maxsize - 1);
+ else if (size > 1)
+ return SETelem_(set, size - 2);
+ }
+ return NULL;
+} /* setlast */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setnew">-</a>
+
+ qh_setnew( setsize )
+ creates and allocates space for a set
+
+ notes:
+ setsize means the number of elements (NOT 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 ((unsigned) size <= (unsigned) 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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setnew_delnthsorted">-</a>
+
+ 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) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): 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, 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, tailsize * SETelemsize);
+ newp += tailsize;
+ }
+ *newp= NULL;
+ return(newset);
+} /* setnew_delnthsorted */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setprint">-</a>
+
+ qh_setprint( fp, string, set )
+ print set elements to fp with identifying string
+
+ notes:
+ never errors
+*/
+void qh_setprint(FILE *fp, char* string, setT *set) {
+ int size, k;
+
+ if (!set)
+ fprintf (fp, "%s set is null\n", string);
+ else {
+ SETreturnsize_(set, size);
+ fprintf (fp, "%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++)
+ fprintf(fp, " %p", set->e[k].p);
+ fprintf(fp, "\n");
+ }
+} /* setprint */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setreplace">-</a>
+
+ 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 {
+ fprintf (qhmem.ferr, "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 */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setsize">-</a>
+
+ qh_setsize( set )
+ returns the size of a set
+
+ notes:
+ errors if set's maxsize is incorrect
+ same as SETreturnsize_(set)
+
+ design:
+ determine actual size of set from maxsize
+*/
+int qh_setsize(setT *set) {
+ int size, *sizep;
+
+ if (!set)
+ return (0);
+ sizep= SETsizeaddr_(set);
+ if ((size= *sizep)) {
+ size--;
+ if (size > set->maxsize) {
+ fprintf (qhmem.ferr, "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 */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="settemp">-</a>
+
+ 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 ((setT **)&qhmem.tempstack, newset);
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_settemp: temp set %p of %d elements, depth %d\n",
+ newset, newset->maxsize, qh_setsize ((setT*)qhmem.tempstack));
+ return newset;
+} /* settemp */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="settempfree">-</a>
+
+ 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);
+ fprintf (qhmem.ferr, "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((setT*)qhmem.tempstack)+1,
+ stackedset, qh_setsize(stackedset));
+ qh_errexit (qhmem_ERRqhull, NULL, NULL);
+ }
+ qh_setfree (set);
+} /* settempfree */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="settempfree_all">-</a>
+
+ 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_((setT *)qhmem.tempstack)
+ qh_setfree(&set);
+ qh_setfree((setT **)&qhmem.tempstack);
+} /* settempfree_all */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="settemppop">-</a>
+
+ 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((setT *)qhmem.tempstack);
+ if (!stackedset) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
+ qh_errexit (qhmem_ERRqhull, NULL, NULL);
+ }
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_settemppop: depth %d temp set %p of %d elements\n",
+ qh_setsize((setT*)qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
+ return stackedset;
+} /* settemppop */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="settemppush">-</a>
+
+ 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) {
+
+ qh_setappend ((setT**)&qhmem.tempstack, set);
+ if (qhmem.IStracing >= 5)
+ fprintf (qhmem.ferr, "qh_settemppush: depth %d temp set %p of %d elements\n",
+ qh_setsize((setT*)qhmem.tempstack), set, qh_setsize(set));
+} /* settemppush */
+
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="settruncate">-</a>
+
+ 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) {
+ fprintf (qhmem.ferr, "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 */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setunique">-</a>
+
+ 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 */
+
+/*-<a href="qh-set.htm#TOC"
+ >-------------------------------<a name="setzero">-</a>
+
+ 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 index, int size) {
+ int count;
+
+ if (index < 0 || index >= size || size > set->maxsize) {
+ fprintf (qhmem.ferr, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", index, size);
+ qh_setprint (qhmem.ferr, "", set);
+ qh_errexit (qhmem_ERRqhull, NULL, NULL);
+ }
+ set->e[set->maxsize].i= size+1; /* may be overwritten */
+ count= size - index + 1; /* +1 for NULL terminator */
+ memset ((char *)SETelemaddr_(set, index, void), 0, count * SETelemsize);
+} /* setzero */
+
+
diff --git a/extern/qhull/src/qset.h b/extern/qhull/src/qset.h
new file mode 100755
index 00000000000..6c0ff758de4
--- /dev/null
+++ b/extern/qhull/src/qset.h
@@ -0,0 +1,468 @@
+/*<html><pre> -<a href="qh-set.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ 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-2002, The Geometry Center
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT; /* a set is a sorted or unsorted array of pointers */
+#endif
+
+/*-<a href="qh-set.htm#TOC"
+>----------------------------------------</a><a name="setT">-</a>
+
+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- =========================*/
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="SETelemsize">-</a>
+
+ SETelemsize
+ size of a set element in bytes
+*/
+#define SETelemsize sizeof(setelemT)
+
+
+/*=========== -macros- =========================*/
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHsetelement_">-</a>
+
+ 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++);)
+
+/*-<a href="qh-set.htm#TOC"
+ >----------------------------------------</a><a name="FOREACHsetelement_i_">-</a>
+
+ 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) )
+
+/*-<a href="qh-set.htm#TOC"
+ >--------------------------------------</a><a name="FOREACHsetelementreverse_">-</a>
+
+ 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))
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHsetelementreverse12_">-</a>
+
+ 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++))
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHelem_">-</a>
+
+ 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)
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------</a><a name="FOREACHset_">-</a>
+
+ 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)
+
+/*-<a href="qh-set.htm#TOC"
+ >-----------------------------------------</a><a name="SETindex_">-</a>
+
+ SETindex_( set, elem )
+ return index of elem in set
+
+ notes:
+ for use with FOREACH iteration
+
+ example:
+ i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((void **)elem##p - (void **)&(set)->e[1].p)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETref_">-</a>
+
+ SETref_( elem )
+ l.h.s. for modifying the current element in a FOREACH iteration
+
+ example:
+ SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETelem_">-</a>
+
+ 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)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETelemt_">-</a>
+
+ 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))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETelemaddr_">-</a>
+
+ 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)))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETfirst_">-</a>
+
+ SETfirst_(set)
+ return first element of set
+
+*/
+#define SETfirst_(set) ((set)->e[0].p)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETfirstt_">-</a>
+
+ SETfirstt_(set, type)
+ return first element of set as a type
+
+*/
+#define SETfirstt_(set, type) ((type*)((set)->e[0].p))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETsecond_">-</a>
+
+ SETsecond_(set)
+ return second element of set
+
+*/
+#define SETsecond_(set) ((set)->e[1].p)
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETsecondt_">-</a>
+
+ SETsecondt_(set, type)
+ return second element of set as a type
+*/
+#define SETsecondt_(set, type) ((type*)((set)->e[1].p))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETaddr_">-</a>
+
+ SETaddr_(set, type)
+ return address of set's elements
+*/
+#define SETaddr_(set,type) ((type **)(&((set)->e[0].p)))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETreturnsize_">-</a>
+
+ 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))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETempty_">-</a>
+
+ SETempty_(set)
+ return true (1) if set is empty
+
+ notes:
+ set may be NULL
+*/
+#define SETempty_(set) (!set || (SETfirst_(set) ? 0:1))
+
+/*-<a href="qh-set.htm#TOC"
+ >---------------------------------------</a><a name="SETtruncate_">-</a>
+
+ SETtruncate_(set)
+ return first element of set
+
+ 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, char *tname, int 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);
+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, 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 index, int size);
+
+
+#endif /* qhDEFset */
diff --git a/extern/qhull/src/qvoronoi.c b/extern/qhull/src/qvoronoi.c
new file mode 100755
index 00000000000..ebeb7367b87
--- /dev/null
+++ b/extern/qhull/src/qvoronoi.c
@@ -0,0 +1,318 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ qvoronoi.c
+ compute Voronoi diagrams and furthest-point Voronoi
+ diagrams using qhull
+
+ see unix.c for full interface
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <console.h>
+#include <Desk.h>
+
+#elif __cplusplus
+extern "C" {
+ int isatty (int);
+}
+
+#elif _MSC_VER
+#include <io.h>
+#define isatty _isatty
+
+#else
+int isatty (int); /* returns 1 if stdin is a tty
+ if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*-<a href="qh-qhull.c#TOC"
+ >-------------------------------</a><a name="prompt">-</a>
+
+ qh_prompt
+ long prompt for qhull
+
+ notes:
+ restricted version of qhull.c
+
+ see:
+ concise prompt below
+*/
+
+/* duplicated in qvoron_f.htm and qvoronoi.htm */
+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.geom.umn.edu/software/qhull %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\
+ Qt - triangulated output\n\
+ QJ - joggled input instead of merged facets\n\
+\n\
+Qhull control options:\n\
+ Qz - add point-at-infinity to Voronoi diagram\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\
+ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt2">-</a>
+
+ 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\
+ 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\
+ 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 G1 d D2 | qvoronoi QJ s p\n\
+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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt3">-</a>
+
+ 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 QJoggle Qsearch_1st Qtriangulate Qupper_voronoi\n\
+ QV_point_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\
+";
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="main">-</a>
+
+ 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/extern/qhull/src/rbox.c b/extern/qhull/src/rbox.c
new file mode 100755
index 00000000000..1c288bddc96
--- /dev/null
+++ b/extern/qhull/src/rbox.c
@@ -0,0 +1,788 @@
+/*<html><pre> -<a href="index.htm#TOC"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ rbox.c
+ Generate input points for qhull.
+
+ notes:
+ 50 points generated for 'rbox D4'
+
+ This code needs a full rewrite. It needs separate procedures for each
+ distribution with common, helper procedures.
+
+ WARNING:
+ incorrect range if qh_RANDOMmax is defined wrong (user.h)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include "user.h"
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <console.h>
+#include <Desk.h>
+#endif
+
+#ifdef _MSC_VER /* Microsoft Visual C++ */
+#pragma warning( disable : 4244) /* conversion from double to int */
+#endif
+
+#define MINVALUE 0.8
+#define MAXdim 200
+#define PI 3.1415926535897932384
+#define DEFAULTzbox 1e6
+
+char prompt[]= "\n\
+-rbox- generate various point distributions. Default is random in cube.\n\
+\n\
+args (any order, space separated): Version: 2001/06/24\n\
+ 3000 number of random points in cube, lens, spiral, sphere or grid\n\
+ D3 dimension 3-d\n\
+ c add a unit cube to the output ('c G2.0' sets size)\n\
+ d add a unit diamond to the output ('d G2.0' sets size)\n\
+ l generate a regular 3-d spiral\n\
+ r generate a regular polygon, ('r s Z1 G0.1' makes a cone)\n\
+ s generate cospherical points\n\
+ x generate random points in simplex, may use 'r' or 'Wn'\n\
+ y same as 'x', plus simplex\n\
+ Pn,m,r add point [n,m,r] first, pads with 0\n\
+\n\
+ Ln lens distribution of radius n. Also 's', 'r', 'G', 'W'.\n\
+ Mn,m,r lattice (Mesh) rotated by [n,-m,0], [m,n,0], [0,0,r], ...\n\
+ '27 M1,0,1' is {0,1,2} x {0,1,2} x {0,1,2}. Try 'M3,4 z'.\n\
+ W0.1 random distribution within 0.1 of the cube's or sphere's surface\n\
+ Z0.5 s random points in a 0.5 disk projected to a sphere\n\
+ Z0.5 s G0.6 same as Z0.5 within a 0.6 gap\n\
+\n\
+ Bn bounding box coordinates, default %2.2g\n\
+ h output as homogeneous coordinates for cdd\n\
+ n remove command line from the first line of output\n\
+ On offset coordinates by n\n\
+ t use time as the random number seed (default is command line)\n\
+ tn use n as the random number seed\n\
+ z print integer coordinates, default 'Bn' is %2.2g\n\
+";
+
+/* ------------------------------ prototypes ----------------*/
+int roundi( double a);
+void out1( double a);
+void out2n( double a, double b);
+void out3n( double a, double b, double c);
+int qh_rand( void);
+void qh_srand( int seed);
+
+
+/* ------------------------------ globals -------------------*/
+
+ FILE *fp;
+ int isinteger= 0;
+ double out_offset= 0.0;
+
+
+/*--------------------------------------------
+-rbox- main procedure of rbox application
+*/
+int main(int argc, char **argv) {
+ int i,j,k;
+ int gendim;
+ int cubesize, diamondsize, seed=0, count, apex;
+ int dim=3 , numpoints= 0, totpoints, addpoints=0;
+ int issphere=0, isaxis=0, iscdd= 0, islens= 0, isregular=0, iswidth=0, addcube=0;
+ int isgap=0, isspiral=0, NOcommand= 0, adddiamond=0, istime=0;
+ int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
+ double width=0.0, gap=0.0, radius= 0.0;
+ double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
+ double *simplex, *simplexp;
+ int nthroot, mult[MAXdim];
+ double norm, factor, randr, rangap, lensangle= 0, lensbase= 1;
+ double anglediff, angle, x, y, cube= 0.0, diamond= 0.0;
+ double box= qh_DEFAULTbox; /* scale all numbers before output */
+ double randmax= qh_RANDOMmax;
+ char command[200], *s, seedbuf[200];
+ time_t timedata;
+
+#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) {
+ printf (prompt, box, DEFAULTzbox);
+ exit(1);
+ }
+ if ((s = strrchr( argv[0], '\\'))) /* Borland gives full path */
+ strcpy (command, s+1);
+ else
+ strcpy (command, argv[0]);
+ if ((s= strstr (command, ".EXE"))
+ || (s= strstr (command, ".exe")))
+ *s= '\0';
+ /* ============= read flags =============== */
+ for (i=1; i < argc; i++) {
+ if (strlen (command) + strlen(argv[i]) + 1 < sizeof(command) ) {
+ strcat (command, " ");
+ strcat (command, argv[i]);
+ }
+ if (isdigit (argv[i][0])) {
+ numpoints= atoi (argv[i]);
+ continue;
+ }
+ if (argv[i][0] == '-')
+ (argv[i])++;
+ switch (argv[i][0]) {
+ case 'c':
+ addcube= 1;
+ if (i+1 < argc && argv[i+1][0] == 'G')
+ cube= (double) atof (&argv[++i][1]);
+ break;
+ case 'd':
+ adddiamond= 1;
+ if (i+1 < argc && argv[i+1][0] == 'G')
+ diamond= (double) atof (&argv[++i][1]);
+ break;
+ case 'h':
+ iscdd= 1;
+ break;
+ case 'l':
+ isspiral= 1;
+ break;
+ case 'n':
+ NOcommand= 1;
+ break;
+ case 'r':
+ isregular= 1;
+ break;
+ case 's':
+ issphere= 1;
+ break;
+ case 't':
+ istime= 1;
+ if (isdigit (argv[i][1]))
+ seed= atoi (&argv[i][1]);
+ else {
+ seed= time (&timedata);
+ sprintf (seedbuf, "%d", seed);
+ strcat (command, seedbuf);
+ }
+ break;
+ case 'x':
+ issimplex= 1;
+ break;
+ case 'y':
+ issimplex2= 1;
+ break;
+ case 'z':
+ isinteger= 1;
+ break;
+ case 'B':
+ box= (double) atof (&argv[i][1]);
+ isbox= 1;
+ break;
+ case 'D':
+ dim= atoi (&argv[i][1]);
+ if (dim < 1
+ || dim > MAXdim) {
+ fprintf (stderr, "rbox error: dim %d too large or too small\n", dim);
+ exit (1);
+ }
+ break;
+ case 'G':
+ if (argv[i][1])
+ gap= (double) atof (&argv[i][1]);
+ else
+ gap= 0.5;
+ isgap= 1;
+ break;
+ case 'L':
+ if (argv[i][1])
+ radius= (double) atof (&argv[i][1]);
+ else
+ radius= 10;
+ islens= 1;
+ break;
+ case 'M':
+ ismesh= 1;
+ s= argv[i]+1;
+ if (*s)
+ meshn= strtod (s, &s);
+ if (*s == ',')
+ meshm= strtod (++s, &s);
+ else
+ meshm= 0.0;
+ if (*s == ',')
+ meshr= strtod (++s, &s);
+ else
+ meshr= sqrt (meshn*meshn + meshm*meshm);
+ if (*s) {
+ fprintf (stderr, "rbox warning: assuming 'M3,4,5' since mesh args are not integers or reals\n");
+ meshn= 3.0, meshm=4.0, meshr=5.0;
+ }
+ break;
+ case 'O':
+ out_offset= (double) atof (&argv[i][1]);
+ break;
+ case 'P':
+ addpoints++;
+ break;
+ case 'W':
+ width= (double) atof (&argv[i][1]);
+ iswidth= 1;
+ break;
+ case 'Z':
+ if (argv[i][1])
+ radius= (double) atof (&argv[i][1]);
+ else
+ radius= 1.0;
+ isaxis= 1;
+ break;
+ default:
+ fprintf (stderr, "rbox warning: unknown flag %s.\nExecute 'rbox' without arguments for documentation.\n", argv[i]);
+ }
+ }
+ /* ============= defaults, constants, and sizes =============== */
+ if (isinteger && !isbox)
+ box= DEFAULTzbox;
+ if (addcube) {
+ cubesize= floor(ldexp(1.0,dim)+0.5);
+ if (cube == 0.0)
+ cube= box;
+ }else
+ cubesize= 0;
+ if (adddiamond) {
+ diamondsize= 2*dim;
+ if (diamond == 0.0)
+ diamond= box;
+ }else
+ diamondsize= 0;
+ if (islens) {
+ if (isaxis) {
+ fprintf (stderr, "rbox error: can not combine 'Ln' with 'Zn'\n");
+ exit(1);
+ }
+ if (radius <= 1.0) {
+ fprintf (stderr, "rbox error: lens radius %.2g should be greater than 1.0\n",
+ radius);
+ exit(1);
+ }
+ lensangle= asin (1.0/radius);
+ lensbase= radius * cos (lensangle);
+ }
+ if (!numpoints) {
+ if (issimplex2)
+ ; /* ok */
+ else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
+ fprintf (stderr, "rbox error: missing count\n");
+ exit(1);
+ }else if (adddiamond + addcube + addpoints)
+ ; /* ok */
+ else {
+ numpoints= 50; /* ./rbox D4 is the test case */
+ issphere= 1;
+ }
+ }
+ if ((issimplex + islens + isspiral + ismesh > 1)
+ || (issimplex + issphere + isspiral + ismesh > 1)) {
+ fprintf (stderr, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
+ exit(1);
+ }
+ fp= stdout;
+ /* ============= print header with total points =============== */
+ if (issimplex || ismesh)
+ totpoints= numpoints;
+ else if (issimplex2)
+ totpoints= numpoints+dim+1;
+ else if (isregular) {
+ totpoints= numpoints;
+ if (dim == 2) {
+ if (islens)
+ totpoints += numpoints - 2;
+ }else if (dim == 3) {
+ if (islens)
+ totpoints += 2 * numpoints;
+ else if (isgap)
+ totpoints += 1 + numpoints;
+ else
+ totpoints += 2;
+ }
+ }else
+ totpoints= numpoints + isaxis;
+ totpoints += cubesize + diamondsize + addpoints;
+ if (iscdd)
+ fprintf(fp, "%s\nbegin\n %d %d %s\n",
+ NOcommand ? "" : command,
+ totpoints, dim+1,
+ isinteger ? "integer" : "real");
+ else if (NOcommand)
+ fprintf(fp, "%d\n%d\n", dim, totpoints);
+ else
+ fprintf(fp, "%d %s\n%d\n", dim, command, totpoints);
+ /* ============= seed randoms =============== */
+ if (istime == 0) {
+ for (s=command; *s; s++) {
+ if (issimplex2 && *s == 'y') /* make 'y' same seed as 'x' */
+ i= 'x';
+ else
+ i= *s;
+ seed= 11*seed + i;
+ }
+ } /* else, seed explicitly set to n or to time */
+ qh_RANDOMseed_(seed);
+ /* ============= explicit points =============== */
+ for (i=1; i < argc; i++) {
+ if (argv[i][0] == 'P') {
+ s= argv[i]+1;
+ count= 0;
+ if (iscdd)
+ out1( 1.0);
+ while (*s) {
+ out1( strtod (s, &s));
+ count++;
+ if (*s) {
+ if (*s++ != ',') {
+ fprintf (stderr, "rbox error: missing comma after coordinate in %s\n\n", argv[i]);
+ exit (1);
+ }
+ }
+ }
+ if (count < dim) {
+ for (k= dim-count; k--; )
+ out1( 0.0);
+ }else if (count > dim) {
+ fprintf (stderr, "rbox error: %d coordinates instead of %d coordinates in %s\n\n",
+ count, dim, argv[i]);
+ exit (1);
+ }
+ fprintf (fp, "\n");
+ }
+ }
+ /* ============= simplex distribution =============== */
+ if (issimplex+issimplex2) {
+ if (!(simplex= malloc( dim * (dim+1) * sizeof(double)))) {
+ fprintf (stderr, "insufficient memory for simplex\n");
+ exit(0);
+ }
+ simplexp= simplex;
+ if (isregular) {
+ for (i= 0; i<dim; i++) {
+ for (k= 0; k<dim; k++)
+ *(simplexp++)= i==k ? 1.0 : 0.0;
+ }
+ for (k= 0; k<dim; k++)
+ *(simplexp++)= -1.0;
+ }else {
+ for (i= 0; i<dim+1; i++) {
+ for (k= 0; k<dim; k++) {
+ randr= qh_RANDOMint;
+ *(simplexp++)= 2.0 * randr/randmax - 1.0;
+ }
+ }
+ }
+ if (issimplex2) {
+ simplexp= simplex;
+ for (i= 0; i<dim+1; i++) {
+ if (iscdd)
+ out1( 1.0);
+ for (k= 0; k<dim; k++)
+ out1( *(simplexp++) * box);
+ fprintf (fp, "\n");
+ }
+ }
+ for (j= 0; j<numpoints; j++) {
+ if (iswidth)
+ apex= qh_RANDOMint % (dim+1);
+ else
+ apex= -1;
+ for (k= 0; k<dim; k++)
+ coord[k]= 0.0;
+ norm= 0.0;
+ for (i= 0; i<dim+1; i++) {
+ randr= qh_RANDOMint;
+ factor= randr/randmax;
+ if (i == apex)
+ factor *= width;
+ norm += factor;
+ for (k= 0; k<dim; k++) {
+ simplexp= simplex + i*dim + k;
+ coord[k] += factor * (*simplexp);
+ }
+ }
+ for (k= 0; k<dim; k++)
+ coord[k] /= norm;
+ if (iscdd)
+ out1( 1.0);
+ for (k=0; k < dim; k++)
+ out1( coord[k] * box);
+ fprintf (fp, "\n");
+ }
+ isregular= 0; /* continue with isbox */
+ numpoints= 0;
+ }
+ /* ============= mesh distribution =============== */
+ if (ismesh) {
+ nthroot= pow (numpoints, 1.0/dim) + 0.99999;
+ for (k= dim; k--; )
+ mult[k]= 0;
+ for (i= 0; i < numpoints; i++) {
+ for (k= 0; k < dim; k++) {
+ if (k == 0)
+ out1( mult[0] * meshn + mult[1] * (-meshm));
+ else if (k == 1)
+ out1( mult[0] * meshm + mult[1] * meshn);
+ else
+ out1( mult[k] * meshr );
+ }
+ fprintf (fp, "\n");
+ for (k= 0; k < dim; k++) {
+ if (++mult[k] < nthroot)
+ break;
+ mult[k]= 0;
+ }
+ }
+ }
+
+ /* ============= regular points for 's' =============== */
+ else if (isregular && !islens) {
+ if (dim != 2 && dim != 3) {
+ fprintf(stderr, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
+ exit(1);
+ }
+ if (!isaxis || radius == 0.0) {
+ isaxis= 1;
+ radius= 1.0;
+ }
+ if (dim == 3) {
+ if (iscdd)
+ out1( 1.0);
+ out3n( 0.0, 0.0, -box);
+ if (!isgap) {
+ if (iscdd)
+ out1( 1.0);
+ out3n( 0.0, 0.0, box);
+ }
+ }
+ angle= 0.0;
+ anglediff= 2.0 * PI/numpoints;
+ for (i=0; i < numpoints; i++) {
+ angle += anglediff;
+ x= radius * cos (angle);
+ y= radius * sin (angle);
+ if (dim == 2) {
+ if (iscdd)
+ out1( 1.0);
+ out2n( x*box, y*box);
+ }else {
+ norm= sqrt (1.0 + x*x + y*y);
+ if (iscdd)
+ out1( 1.0);
+ out3n( box*x/norm, box*y/norm, box/norm);
+ if (isgap) {
+ x *= 1-gap;
+ y *= 1-gap;
+ norm= sqrt (1.0 + x*x + y*y);
+ if (iscdd)
+ out1( 1.0);
+ out3n( box*x/norm, box*y/norm, box/norm);
+ }
+ }
+ }
+ }
+ /* ============= regular points for 'r Ln D2' =============== */
+ else if (isregular && islens && dim == 2) {
+ double cos_0;
+
+ angle= lensangle;
+ anglediff= 2 * lensangle/(numpoints - 1);
+ cos_0= cos (lensangle);
+ for (i=0; i < numpoints; i++, angle -= anglediff) {
+ x= radius * sin (angle);
+ y= radius * (cos (angle) - cos_0);
+ if (iscdd)
+ out1( 1.0);
+ out2n( x*box, y*box);
+ if (i != 0 && i != numpoints - 1) {
+ if (iscdd)
+ out1( 1.0);
+ out2n( x*box, -y*box);
+ }
+ }
+ }
+ /* ============= regular points for 'r Ln D3' =============== */
+ else if (isregular && islens && dim != 2) {
+ if (dim != 3) {
+ fprintf(stderr, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
+ exit(1);
+ }
+ angle= 0.0;
+ anglediff= 2* PI/numpoints;
+ if (!isgap) {
+ isgap= 1;
+ gap= 0.5;
+ }
+ offset= sqrt (radius * radius - (1-gap)*(1-gap)) - lensbase;
+ for (i=0; i < numpoints; i++, angle += anglediff) {
+ x= cos (angle);
+ y= sin (angle);
+ if (iscdd)
+ out1( 1.0);
+ out3n( box*x, box*y, 0);
+ x *= 1-gap;
+ y *= 1-gap;
+ if (iscdd)
+ out1( 1.0);
+ out3n( box*x, box*y, box * offset);
+ if (iscdd)
+ out1( 1.0);
+ out3n( box*x, box*y, -box * offset);
+ }
+ }
+ /* ============= apex of 'Zn' distribution + gendim =============== */
+ else {
+ if (isaxis) {
+ gendim= dim-1;
+ if (iscdd)
+ out1( 1.0);
+ for (j=0; j < gendim; j++)
+ out1( 0.0);
+ out1( -box);
+ fprintf (fp, "\n");
+ }else if (islens)
+ gendim= dim-1;
+ else
+ gendim= dim;
+ /* ============= generate random point in unit cube =============== */
+ for (i=0; i < numpoints; i++) {
+ norm= 0.0;
+ for (j=0; j < gendim; j++) {
+ randr= qh_RANDOMint;
+ coord[j]= 2.0 * randr/randmax - 1.0;
+ norm += coord[j] * coord[j];
+ }
+ norm= sqrt (norm);
+ /* ============= dim-1 point of 'Zn' distribution ========== */
+ if (isaxis) {
+ if (!isgap) {
+ isgap= 1;
+ gap= 1.0;
+ }
+ randr= qh_RANDOMint;
+ rangap= 1.0 - gap * randr/randmax;
+ factor= radius * rangap / norm;
+ for (j=0; j<gendim; j++)
+ coord[j]= factor * coord[j];
+ /* ============= dim-1 point of 'Ln s' distribution =========== */
+ }else if (islens && issphere) {
+ if (!isgap) {
+ isgap= 1;
+ gap= 1.0;
+ }
+ randr= qh_RANDOMint;
+ rangap= 1.0 - gap * randr/randmax;
+ factor= rangap / norm;
+ for (j=0; j<gendim; j++)
+ coord[j]= factor * coord[j];
+ /* ============= dim-1 point of 'Ln' distribution ========== */
+ }else if (islens && !issphere) {
+ if (!isgap) {
+ isgap= 1;
+ gap= 1.0;
+ }
+ j= qh_RANDOMint % gendim;
+ if (coord[j] < 0)
+ coord[j]= -1.0 - coord[j] * gap;
+ else
+ coord[j]= 1.0 - coord[j] * gap;
+ /* ============= point of 'l' distribution =============== */
+ }else if (isspiral) {
+ if (dim != 3) {
+ fprintf(stderr, "rbox error: spiral distribution is available only in 3d\n\n");
+ exit(1);
+ }
+ coord[0]= cos(2*PI*i/(numpoints - 1));
+ coord[1]= sin(2*PI*i/(numpoints - 1));
+ coord[2]= 2.0*(double)i/(double)(numpoints-1) - 1.0;
+ /* ============= point of 's' distribution =============== */
+ }else if (issphere) {
+ factor= 1.0/norm;
+ if (iswidth) {
+ randr= qh_RANDOMint;
+ factor *= 1.0 - width * randr/randmax;
+ }
+ for (j=0; j<dim; j++)
+ coord[j]= factor * coord[j];
+ }
+ /* ============= project 'Zn s' point in to sphere =============== */
+ if (isaxis && issphere) {
+ coord[dim-1]= 1.0;
+ norm= 1.0;
+ for (j=0; j<gendim; j++)
+ norm += coord[j] * coord[j];
+ norm= sqrt (norm);
+ for (j=0; j<dim; j++)
+ coord[j]= coord[j] / norm;
+ if (iswidth) {
+ randr= qh_RANDOMint;
+ coord[dim-1] *= 1 - width * randr/randmax;
+ }
+ /* ============= project 'Zn' point onto cube =============== */
+ }else if (isaxis && !issphere) { /* not very interesting */
+ randr= qh_RANDOMint;
+ coord[dim-1]= 2.0 * randr/randmax - 1.0;
+ /* ============= project 'Ln' point out to sphere =============== */
+ }else if (islens) {
+ coord[dim-1]= lensbase;
+ for (j=0, norm= 0; j<dim; j++)
+ norm += coord[j] * coord[j];
+ norm= sqrt (norm);
+ for (j=0; j<dim; j++)
+ coord[j]= coord[j] * radius/ norm;
+ coord[dim-1] -= lensbase;
+ if (iswidth) {
+ randr= qh_RANDOMint;
+ coord[dim-1] *= 1 - width * randr/randmax;
+ }
+ if (qh_RANDOMint > randmax/2)
+ coord[dim-1]= -coord[dim-1];
+ /* ============= project 'Wn' point toward boundary =============== */
+ }else if (iswidth && !issphere) {
+ j= qh_RANDOMint % gendim;
+ if (coord[j] < 0)
+ coord[j]= -1.0 - coord[j] * width;
+ else
+ coord[j]= 1.0 - coord[j] * width;
+ }
+ /* ============= write point =============== */
+ if (iscdd)
+ out1( 1.0);
+ for (k=0; k < dim; k++)
+ out1( coord[k] * box);
+ fprintf (fp, "\n");
+ }
+ }
+ /* ============= write cube vertices =============== */
+ if (addcube) {
+ for (j=0; j<cubesize; j++) {
+ if (iscdd)
+ out1( 1.0);
+ for (k=dim-1; k>=0; k--) {
+ if (j & ( 1 << k))
+ out1( cube);
+ else
+ out1( -cube);
+ }
+ fprintf (fp, "\n");
+ }
+ }
+ /* ============= write diamond vertices =============== */
+ if (adddiamond) {
+ for (j=0; j<diamondsize; j++) {
+ if (iscdd)
+ out1( 1.0);
+ for (k=dim-1; k>=0; k--) {
+ if (j/2 != k)
+ out1( 0.0);
+ else if (j & 0x1)
+ out1( diamond);
+ else
+ out1( -diamond);
+ }
+ fprintf (fp, "\n");
+ }
+ }
+ if (iscdd)
+ fprintf (fp, "end\nhull\n");
+ return 0;
+ } /* rbox */
+
+/*------------------------------------------------
+-outxxx - output functions
+*/
+int roundi( double a) {
+ if (a < 0.0) {
+ if (a - 0.5 < INT_MIN) {
+ fprintf(stderr, "rbox input error: coordinate %2.2g is too large. Reduce 'Bn'\n", a);
+ exit (1);
+ }
+ return a - 0.5;
+ }else {
+ if (a + 0.5 > INT_MAX) {
+ fprintf(stderr, "rbox input error: coordinate %2.2g is too large. Reduce 'Bn'\n", a);
+ exit (1);
+ }
+ return a + 0.5;
+ }
+} /* roundi */
+
+void out1(double a) {
+
+ if (isinteger)
+ fprintf(fp, "%d ", roundi( a+out_offset));
+ else
+ fprintf(fp, qh_REAL_1, a+out_offset);
+} /* out1 */
+
+void out2n( double a, double b) {
+
+ if (isinteger)
+ fprintf(fp, "%d %d\n", roundi(a+out_offset), roundi(b+out_offset));
+ else
+ fprintf(fp, qh_REAL_2n, a+out_offset, b+out_offset);
+} /* out2n */
+
+void out3n( double a, double b, double c) {
+
+ if (isinteger)
+ fprintf(fp, "%d %d %d\n", roundi(a+out_offset), roundi(b+out_offset), roundi(c+out_offset));
+ else
+ fprintf(fp, qh_REAL_3n, a+out_offset, b+out_offset, c+out_offset);
+} /* out3n */
+
+/*-------------------------------------------------
+-rand & srand- generate pseudo-random number between 1 and 2^31 -2
+ from Park & Miller's minimimal standard random number generator
+ Communications of the ACM, 31:1192-1201, 1988.
+notes:
+ does not use 0 or 2^31 -1
+ this is silently enforced by qh_srand()
+ copied from geom2.c
+*/
+static int seed = 1; /* global static */
+
+int qh_rand( void) {
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773 /* m div a */
+#define qh_rand_r 2836 /* m mod a */
+ int lo, hi, test;
+
+ hi = seed / qh_rand_q; /* seed div q */
+ lo = seed % qh_rand_q; /* seed mod q */
+ test = qh_rand_a * lo - qh_rand_r * hi;
+ if (test > 0)
+ seed= test;
+ else
+ seed= test + qh_rand_m;
+ return seed;
+} /* rand */
+
+void qh_srand( int newseed) {
+ if (newseed < 1)
+ seed= 1;
+ else if (newseed >= qh_rand_m)
+ seed= qh_rand_m - 1;
+ else
+ seed= newseed;
+} /* qh_srand */
+
diff --git a/extern/qhull/src/stat.c b/extern/qhull/src/stat.c
new file mode 100755
index 00000000000..e8d21fe69db
--- /dev/null
+++ b/extern/qhull/src/stat.c
@@ -0,0 +1,700 @@
+/*<html><pre> -<a href="qh-stat.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ stat.c
+ contains all statistics that are collected for qhull
+
+ see qh-stat.htm and stat.h
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#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 ================*/
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="allstatA">-</a>
+
+ 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 (not 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 (not above max_outside)", -1);
+ zdef_(zinc, Znotgood, "points ignored (not 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);
+ zdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
+ zzdef_(zinc, Zcheckpart, " ave. distance tests per check", Ztotcheck);
+}
+void qh_allstatD(void) {
+ 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);
+ 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_(wadd, Wmaxout, "difference in max_outside at final check", -1);
+}
+void qh_allstatE(void) {
+ 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 */
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="allstatistics">-</a>
+
+ 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
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="collectstatistics">-</a>
+
+ 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 */
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="freestatistics">-</a>
+
+ qh_freestatistics( )
+ free memory used for statistics
+*/
+void qh_freestatistics (void) {
+
+#if qh_QHpointer
+ free (qh_qhstat);
+ qh_qhstat= NULL;
+#endif
+} /* freestatistics */
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="initstatistics">-</a>
+
+ qh_initstatistics( )
+ allocate and initialize statistics
+
+ notes:
+ uses malloc() instead of qh_memalloc() since mem.c not set up yet
+*/
+void qh_initstatistics (void) {
+ int i;
+ realT realx;
+ int intx;
+
+#if qh_QHpointer
+ if (!(qh_qhstat= (qhstatT *)malloc (sizeof(qhstatT)))) {
+ fprintf (qhmem.ferr, "qhull error (qh_initstatistics): insufficient memory\n");
+ exit (1); /* 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 > sizeof(qhstat id)) {
+ fprintf (qhmem.ferr, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\
+ qhstat.next %d should be <= sizeof(qhstat id) %d\n", qhstat next, 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]) {
+ fprintf (qhmem.ferr, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
+ qhstat id[i], i, j);
+ }
+ }
+ }
+#endif
+ exit (1); /* 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 */
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="newstats">-</a>
+
+ qh_newstats( )
+ returns True if statistics for zdoc
+
+ returns:
+ next zdoc
+*/
+boolT qh_newstats (int index, int *nextindex) {
+ boolT isnew= False;
+ int start, i;
+
+ if (qhstat type[qhstat id[index]] == zdoc)
+ start= index+1;
+ else
+ start= index;
+ 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 */
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="nostatistic">-</a>
+
+ 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
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="printallstatistics">-</a>
+
+ qh_printallstatistics( fp, string )
+ print all statistics with header 'string'
+*/
+void qh_printallstatistics (FILE *fp, char *string) {
+
+ qh_allstatistics();
+ qh_collectstatistics();
+ qh_printstatistics (fp, string);
+ qh_memstatistics (fp);
+}
+
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="printstatistics">-</a>
+
+ 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, 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);
+ fprintf (fp, "\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);
+ fprintf (fp, "\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)
+ fprintf(fp, "\
+ %6.2g max. distance for near-inside points\n", qh NEARinside);
+ if (qh premerge_cos < REALmax/2) fprintf (fp, "\
+ %6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
+ if (qh PREmerge) fprintf (fp, "\
+ %6.2g radius of pre-merge centrum\n", qh premerge_centrum);
+ if (qh postmerge_cos < REALmax/2) fprintf (fp, "\
+ %6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
+ if (qh POSTmerge) fprintf (fp, "\
+ %6.2g radius of post-merge centrum\n", qh postmerge_centrum);
+ fprintf (fp, "\
+ %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++)
+ fprintf (fp, "%6.2e ", qh NEARzero[k]);
+ fprintf (fp, "\n\n");
+ for (i=0 ; i < qhstat next; )
+ qh_printstats (fp, i, &i);
+} /* printstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="printstatlevel">-</a>
+
+ 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) {
+ fprintf (fp, "%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)
+ fprintf (fp, " *0 cnt*");
+ else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
+ fprintf (fp, "%7.2g", qhstat stats[id].r);
+ else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
+ fprintf (fp, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
+ else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
+ fprintf (fp, "%7d", qhstat stats[id].i);
+ else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
+ fprintf (fp, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
+ fprintf (fp, " %s\n", qhstat doc[id]);
+} /* printstatlevel */
+
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="printstats">-</a>
+
+ qh_printstats( fp, index, nextindex )
+ print statistics for a zdoc group
+
+ returns:
+ next zdoc if non-null
+*/
+void qh_printstats (FILE *fp, int index, int *nextindex) {
+ int j, nexti;
+
+ if (qh_newstats (index, &nexti)) {
+ fprintf (fp, "\n");
+ for (j=index; j<nexti; j++)
+ qh_printstatlevel (fp, qhstat id[j], 0);
+ }
+ if (nextindex)
+ *nextindex= nexti;
+} /* printstats */
+
+#if qh_KEEPstatistics
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="stddev">-</a>
+
+ 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/extern/qhull/src/stat.h b/extern/qhull/src/stat.h
new file mode 100755
index 00000000000..1dae54ed21d
--- /dev/null
+++ b/extern/qhull/src/stat.h
@@ -0,0 +1,520 @@
+ /*<html><pre> -<a href="qh-stat.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ stat.h
+ contains all statistics that are collected for qhull
+
+ see qh-stat.htm and stat.c
+
+ copyright (c) 1993-2002, The Geometry Center
+
+ 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
+
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="KEEPstatistics">-</a>
+
+ qh_KEEPstatistics
+ 0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="statistics">-</a>
+
+ 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">-</a>
+ remove leaders with query-replace-regexp [ ^I]+ (
+*/
+#if qh_KEEPstatistics
+enum statistics { /* alphabetical after Z/W */
+ Zacoplanar,
+ Wacoplanarmax,
+ Wacoplanartot,
+ Zangle,
+ Wangle,
+ Wanglemax,
+ Wanglemin,
+ Zangletests,
+ Wareatot,
+ Wareamax,
+ Wareamin,
+ Zavoidold,
+ Wavoidoldmax,
+ Wavoidoldtot,
+ Zback0,
+ Zbestcentrum,
+ Zbestdist,
+ 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,
+ Zvisvertextot,
+ Zvisvertexmax,
+ Zwidefacet,
+ Zwidevertices,
+ ZEND};
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="ZZstat">-</a>
+
+ 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 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,
+ Ztotmerge,
+ ZEND};
+#endif
+
+/*-<a href="qh-stat.htm#TOC"
+ >-------------------------------</a><a name="ztype">-</a>
+
+ 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 =============*/
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="MAYdebugx">-</a>
+
+ MAYdebugx
+ define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zdef_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zinc_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zadd_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zval_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zmax_">-</a>
+
+ 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
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="zmin_">-</a>
+
+ 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 ==============*/
+
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="intrealT">-</a>
+
+ intrealT
+ union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT; /* union of int and realT */
+union intrealT {
+ int i;
+ realT r;
+};
+
+/*-<a href="qh-stat.htm#TOC"
+ >--------------------------------</a><a name="qhstat">-</a>
+
+ qhstat
+ global data structure for statistics
+
+ 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 qhull.h
+
+ allocated in stat.c
+*/
+typedef struct qhstatT qhstatT;
+#if qh_QHpointer
+#define qhstat qh_qhstat->
+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 */
+ 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 index, int *nextindex);
+boolT qh_nostatistic (int i);
+void qh_printallstatistics (FILE *fp, char *string);
+void qh_printstatistics (FILE *fp, char *string);
+void qh_printstatlevel (FILE *fp, int id, int start);
+void qh_printstats (FILE *fp, int index, int *nextindex);
+realT qh_stddev (int num, realT tot, realT tot2, realT *ave);
+
+#endif /* qhDEFstat */
diff --git a/extern/qhull/src/unix.c b/extern/qhull/src/unix.c
new file mode 100755
index 00000000000..5ec5feab16c
--- /dev/null
+++ b/extern/qhull/src/unix.c
@@ -0,0 +1,376 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ unix.c
+ command line interface to qhull
+ includes SIOUX interface for Macintoshes
+
+ see qh-qhull.htm
+
+ copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include <SIOUX.h>
+#include <Files.h>
+#include <console.h>
+#include <Desk.h>
+
+#elif __cplusplus
+extern "C" {
+ int isatty (int);
+}
+
+#elif _MSC_VER
+#include <io.h>
+#define isatty _isatty
+
+#else
+int isatty (int); /* returns 1 if stdin is a tty
+ if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt">-</a>
+
+ qh_prompt
+ long prompt for qhull
+
+ see:
+ concise prompt below
+*/
+char qh_prompta[]= "\n\
+qhull- compute convex hulls and related structures.\n\
+ http://www.geom.umn.edu/software/qhull %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\
+ 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\
+ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt2">-</a>
+
+ qh_prompt2
+ synopsis for qhull
+*/
+char qh_prompt2[]= "\n\
+qhull- compute convex hulls and related structures. %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 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 (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 QJ 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) */
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="prompt3">-</a>
+
+ 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\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 Tcheck_often Tstatistics Tverify Tz_stdout\n\
+ TFacet_log TInput_file TPoint_trace TMerge_trace TOutput_file\n\
+ 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\
+";
+
+/*-<a href="qh-qhull.htm#TOC"
+ >-------------------------------</a><a name="main">-</a>
+
+ 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/extern/qhull/src/user.c b/extern/qhull/src/user.c
new file mode 100755
index 00000000000..94b31aaf99f
--- /dev/null
+++ b/extern/qhull/src/user.c
@@ -0,0 +1,324 @@
+/*<html><pre> -<a href="qh-user.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ user.c
+ user redefinable functions
+
+ see README.txt see COPYING.txt for copyright information.
+
+ see qhull.h for data structures, macros, and user-callable functions.
+
+ see user_eg.c, unix.c, and qhull_interface.cpp for examples.
+
+ see user.h for user-definable constants
+
+ use qh_NOmem in mem.h to turn off memory management
+ use qh_NOmerge in user.h to turn off facet merging
+ set qh_KEEPstatistics in user.h to 0 to turn off statistics
+
+ This is unsupported software. You're welcome to make changes,
+ but you're on your own if something goes wrong. Use 'Tc' to
+ check frequently. Usually qhull will report an error if
+ a data structure becomes inconsistent. If so, it also reports
+ the last point added to the hull, e.g., 102. You can then trace
+ the execution of qhull with "T4P102".
+
+ Please report any errors that you fix to qhull@geom.umn.edu
+
+ call_qhull is a template for calling qhull from within your application
+
+ if you recompile and load this module, then user.o will not be loaded
+ from qhull.a
+
+ you can add additional quick allocation sizes in qh_user_memsizes
+
+ if the other functions here are redefined to not use qh_print...,
+ then io.o will not be loaded from qhull.a. See user_eg.c for an
+ example. We recommend keeping io.o for the extra debugging
+ information it supplies.
+*/
+
+#include "qhull_a.h"
+
+/*-<a href="qh-user.htm#TOC"
+ >-------------------------------</a><a name="call_qhull">-</a>
+
+ qh_call_qhull( void )
+ template for calling qhull from inside your program
+ remove #if 0, #endif to compile
+
+ returns:
+ exit code (see qh_ERR... in qhull.h)
+ all memory freed
+
+ notes:
+ This can be called any number of times.
+
+ see:
+ qh_call_qhull_once()
+
+*/
+#if 0
+{
+ int dim; /* dimension of points */
+ int numpoints; /* number of points */
+ coordT *points; /* array of coordinates for each point */
+ boolT ismalloc; /* True if qhull should free points in qh_freeqhull() or reallocation */
+ char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
+ FILE *outfile= stdout; /* output from qh_produce_output()
+ use NULL to skip qh_produce_output() */
+ FILE *errfile= stderr; /* error messages from qhull code */
+ int exitcode; /* 0 if no error from qhull */
+ facetT *facet; /* set by FORALLfacets */
+ int curlong, totlong; /* memory remaining after qh_memfreeshort */
+
+ /* initialize dim, numpoints, points[], ismalloc here */
+ exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ if (!exitcode) { /* if no error */
+ /* 'qh facet_list' contains the convex hull */
+ FORALLfacets {
+ /* ... your code ... */
+ }
+ }
+ qh_freeqhull(!qh_ALL);
+ qh_memfreeshort (&curlong, &totlong);
+ if (curlong || totlong)
+ fprintf (errfile, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+}
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >-------------------------------</a><a name="new_qhull">-</a>
+
+ qh_new_qhull( dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
+ build new qhull data structure and return exitcode (0 if no errors)
+
+ notes:
+ do not modify points until finished with results.
+ The qhull data structure contains pointers into the points array.
+ do not call qhull functions before qh_new_qhull().
+ The qhull data structure is not initialized until qh_new_qhull().
+
+ outfile may be null
+ qhull_cmd must start with "qhull "
+ projects points to a new point array for Delaunay triangulations ('d' and 'v')
+ transforms points into a new point array for halfspace intersection ('H')
+
+
+ To allow multiple, concurrent calls to qhull()
+ - set qh_QHpointer in user.h
+ - use qh_save_qhull and qh_restore_qhull to swap the global data structure between calls.
+ - use qh_freeqhull(qh_ALL) to free intermediate convex hulls
+
+ see:
+ user_eg.c for an example
+*/
+int qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc,
+ char *qhull_cmd, FILE *outfile, FILE *errfile) {
+ int exitcode, hulldim;
+ boolT new_ismalloc;
+ static boolT firstcall = True;
+ coordT *new_points;
+
+ if (firstcall) {
+ qh_meminit (errfile);
+ firstcall= False;
+ }
+ if (strncmp (qhull_cmd,"qhull ", 6)) {
+ fprintf (errfile, "qh_new_qhull: start qhull_cmd argument with \"qhull \"\n");
+ exit(1);
+ }
+ qh_initqhull_start (NULL, outfile, errfile);
+ trace1(( qh ferr, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));
+ exitcode = setjmp (qh errexit);
+ if (!exitcode)
+ {
+ qh NOerrexit = False;
+ qh_initflags (qhull_cmd);
+ if (qh DELAUNAY)
+ qh PROJECTdelaunay= True;
+ if (qh HALFspace) {
+ /* points is an array of halfspaces,
+ the last coordinate of each halfspace is its offset */
+ hulldim= dim-1;
+ qh_setfeasible (hulldim);
+ new_points= qh_sethalfspace_all (dim, numpoints, points, qh feasible_point);
+ new_ismalloc= True;
+ if (ismalloc)
+ free (points);
+ }else {
+ hulldim= dim;
+ new_points= points;
+ new_ismalloc= ismalloc;
+ }
+ qh_init_B (new_points, numpoints, hulldim, new_ismalloc);
+ qh_qhull();
+ qh_check_output();
+ if (outfile)
+ qh_produce_output();
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points();
+ }
+ qh NOerrexit = True;
+ return exitcode;
+} /* new_qhull */
+
+/*-<a href="qh-user.htm#TOC"
+ >-------------------------------</a><a name="errexit">-</a>
+
+ qh_errexit( exitcode, facet, ridge )
+ report and exit from an error
+ report facet and ridge if non-NULL
+ reports useful information such as last point processed
+ set qh.FORCEoutput to print neighborhood of facet
+
+ see:
+ qh_errexit2() in qhull.c for printing 2 facets
+
+ design:
+ check for error within error processing
+ compute qh.hulltime
+ print facet and ridge (if any)
+ report commandString, options, qh.furthest_id
+ print summary and statistics (including precision statistics)
+ if qh_ERRsingular
+ print help text for singular data set
+ exit program via long jump (if defined) or exit()
+*/
+void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
+
+ if (qh ERREXITcalled) {
+ fprintf (qh ferr, "\nqhull error while processing previous error. Exit program\n");
+ exit(1);
+ }
+ qh ERREXITcalled= True;
+ if (!qh QHULLfinished)
+ qh hulltime= qh_CPUclock - qh hulltime;
+ qh_errprint("ERRONEOUS", facet, NULL, ridge, NULL);
+ fprintf (qh ferr, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
+ fprintf(qh ferr, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+ if (qh furthest_id >= 0) {
+ fprintf(qh ferr, "Last point added to hull was p%d.", qh furthest_id);
+ if (zzval_(Ztotmerge))
+ fprintf(qh ferr, " Last merge was #%d.", zzval_(Ztotmerge));
+ if (qh QHULLfinished)
+ fprintf(qh ferr, "\nQhull has finished constructing the hull.");
+ else if (qh POSTmerging)
+ fprintf(qh ferr, "\nQhull has started post-merging.");
+ fprintf (qh ferr, "\n");
+ }
+ if (qh FORCEoutput && (qh QHULLfinished || (!facet && !ridge)))
+ qh_produce_output();
+ else {
+ if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh hull_dim+1) {
+ fprintf (qh ferr, "\nAt error exit:\n");
+ qh_printsummary (qh ferr);
+ if (qh PRINTstatistics) {
+ qh_collectstatistics();
+ qh_printstatistics(qh ferr, "at error exit");
+ qh_memstatistics (qh ferr);
+ }
+ }
+ if (qh PRINTprecision)
+ qh_printstats (qh ferr, qhstat precision, NULL);
+ }
+ if (!exitcode)
+ exitcode= qh_ERRqhull;
+ else if (exitcode == qh_ERRsingular)
+ qh_printhelp_singular(qh ferr);
+ else if (exitcode == qh_ERRprec && !qh PREmerge)
+ qh_printhelp_degenerate (qh ferr);
+ if (qh NOerrexit) {
+ fprintf (qh ferr, "qhull error while ending program. Exit program\n");
+ exit(1);
+ }
+ qh NOerrexit= True;
+ longjmp(qh errexit, exitcode);
+} /* errexit */
+
+
+/*-<a href="qh-user.htm#TOC"
+ >-------------------------------</a><a name="errprint">-</a>
+
+ qh_errprint( fp, string, atfacet, otherfacet, atridge, atvertex )
+ prints out the information of facets and ridges to fp
+ also prints neighbors and geomview output
+
+ notes:
+ except for string, any parameter may be NULL
+*/
+void qh_errprint(char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+ int i;
+
+ if (atfacet) {
+ fprintf(qh ferr, "%s FACET:\n", string);
+ qh_printfacet(qh ferr, atfacet);
+ }
+ if (otherfacet) {
+ fprintf(qh ferr, "%s OTHER FACET:\n", string);
+ qh_printfacet(qh ferr, otherfacet);
+ }
+ if (atridge) {
+ fprintf(qh ferr, "%s RIDGE:\n", string);
+ qh_printridge(qh ferr, atridge);
+ if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)
+ qh_printfacet(qh ferr, atridge->top);
+ if (atridge->bottom
+ && atridge->bottom != atfacet && atridge->bottom != otherfacet)
+ qh_printfacet(qh ferr, atridge->bottom);
+ if (!atfacet)
+ atfacet= atridge->top;
+ if (!otherfacet)
+ otherfacet= otherfacet_(atridge, atfacet);
+ }
+ if (atvertex) {
+ fprintf(qh ferr, "%s VERTEX:\n", string);
+ qh_printvertex (qh ferr, atvertex);
+ }
+ if (qh fout && qh FORCEoutput && atfacet && !qh QHULLfinished && !qh IStracing) {
+ fprintf(qh ferr, "ERRONEOUS and NEIGHBORING FACETS to output\n");
+ for (i= 0; i < qh_PRINTEND; i++) /* use fout for geomview output */
+ qh_printneighborhood (qh fout, qh PRINTout[i], atfacet, otherfacet,
+ !qh_ALL);
+ }
+} /* errprint */
+
+
+/*-<a href="qh-user.htm#TOC"
+ >-------------------------------</a><a name="printfacetlist">-</a>
+
+ qh_printfacetlist( fp, facetlist, facets, printall )
+ print all fields for a facet list and/or set of facets to fp
+ if !printall,
+ only prints good facets
+
+ notes:
+ also prints all vertices
+*/
+void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
+ facetT *facet, **facetp;
+
+ qh_printbegin (qh ferr, qh_PRINTfacets, facetlist, facets, printall);
+ FORALLfacet_(facetlist)
+ qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
+ FOREACHfacet_(facets)
+ qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
+ qh_printend (qh ferr, qh_PRINTfacets, facetlist, facets, printall);
+} /* printfacetlist */
+
+
+/*-<a href="qh-globa.htm#TOC"
+ >-------------------------------</a><a name="user_memsizes">-</a>
+
+ qh_user_memsizes()
+ allocate up to 10 additional, quick allocation sizes
+
+ notes:
+ increase maximum number of allocations in qh_initqhull_mem()
+*/
+void qh_user_memsizes (void) {
+
+ /* qh_memsize (size); */
+} /* user_memsizes */
+
diff --git a/extern/qhull/src/user.h b/extern/qhull/src/user.h
new file mode 100755
index 00000000000..79558967a52
--- /dev/null
+++ b/extern/qhull/src/user.h
@@ -0,0 +1,762 @@
+/*<html><pre> -<a href="qh-user.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ user.h
+ user redefinable constants
+
+ see qh-user.htm. see COPYING for copyright information.
+
+ before reading any code, review qhull.h for data structure definitions and
+ the "qh" macro.
+*/
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/*============= data types and configuration macros ==========*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="realT">-</a>
+
+ realT
+ set the size of floating point numbers
+
+ qh_REALdigits
+ maximimum number of significant digits
+
+ qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+ format strings for printf
+
+ qh_REALmax, qh_REALmin
+ maximum and minimum (near zero) values
+
+ qh_REALepsilon
+ machine roundoff. Maximum roundoff error for addition and multiplication.
+
+ notes:
+ Select whether to store floating point numbers in single precision (float)
+ or double precision (double).
+
+ Use 'float' to save about 8% in time and 25% in space. This is particularly
+ help if high-d where convex hulls are space limited. Using 'float' also
+ reduces the printed size of Qhull's output since numbers have 8 digits of
+ precision.
+
+ Use 'double' when greater arithmetic precision is needed. This is needed
+ for Delaunay triangulations and Voronoi diagrams when you are not merging
+ facets.
+
+ If 'double' gives insufficient precision, your data probably includes
+ degeneracies. If so you should use facet merging (done by default)
+ or exact arithmetic (see imprecision section of manual, qh-impre.htm).
+ You may also use option 'Po' to force output despite precision errors.
+
+ You may use 'long double', but many format statements need to be changed
+ and you may need a 'long double' square root routine. S. Grundmann
+ (sg@eeiwzb.et.tu-dresden.de) has done this. He reports that the code runs
+ much slower with little gain in precision.
+
+ WARNING: on some machines, int f(){realT a= REALmax;return (a == REALmax);}
+ returns False. Use (a > REALmax/2) instead of (a == REALmax).
+
+ REALfloat = 1 all numbers are 'float' type
+ = 0 all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8 /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16 /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="CPUclock">-</a>
+
+ qh_CPUclock
+ define the clock() function for reporting the total time spent by Qhull
+ returns CPU ticks as a 'long int'
+ qh_CPUclock is only used for reporting the total time spent by Qhull
+
+ qh_SECticks
+ the number of clock ticks per second
+
+ notes:
+ looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+ to define a custom clock, set qh_CLOCKtype to 0
+
+ if your system does not use clock() to return CPU ticks, replace
+ qh_CPUclock with the corresponding function. It is converted
+ to unsigned long to prevent wrap-around during long runs.
+
+
+ Set qh_CLOCKtype to
+
+ 1 for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+ Note: may fail if more than 1 hour elapsed time
+
+ 2 use qh_clock() with POSIX times() (see global.c)
+*/
+#define qh_CLOCKtype 1 /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined (CLOCKS_PER_SECOND)
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined (CLOCKS_PER_SEC)
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined (CLK_TCK)
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock qh_clock() /* return CPU clock */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="RANDOM">-</a>
+
+ qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+ define random number generator
+
+ qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.
+ qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+ Set qh_RANDOMtype (default 5) to:
+ 1 for random() with 31 bits (UCB)
+ 2 for rand() with RAND_MAX or 15 bits (system 5)
+ 3 for rand() with 31 bits (Sun)
+ 4 for lrand48() with 31 bits (Solaris)
+ 5 for qh_rand() with 31 bits (included with Qhull)
+
+ notes:
+ Random numbers are used by rbox to generate point sets. Random
+ numbers are used by Qhull to rotate the input ('QRn' option),
+ simulate a randomized algorithm ('Qr' option), and to simulate
+ roundoff errors ('Rn' option).
+
+ Random number generators differ between systems. Most systems provide
+ rand() but the period varies. The period of rand() is not critical
+ since qhull does not normally use random numbers.
+
+ The default generator is Park & Miller's minimal standard random
+ number generator [CACM 31:1195 '88]. It is included with Qhull.
+
+ If qh_RANDOMmax is wrong, qhull will report a warning and Geomview
+ output will likely be invisible.
+*/
+#define qh_RANDOMtype 5 /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767) /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, Sun */
+#define qh_RANDOMint rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)
+#define qh_RANDOMmax ((realT)2147483646UL) /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand()
+#define qh_RANDOMseed_(seed) qh_srand(seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="ORIENTclock">-</a>
+
+ qh_ORIENTclock
+ 0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0
+
+
+/*========= performance related constants =========*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="HASHfactor">-</a>
+
+ qh_HASHfactor
+ total hash slots / used hash slots. Must be at least 1.1.
+
+ notes:
+ =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="VERIFYdirect">-</a>
+
+ qh_VERIFYdirect
+ with 'Tv' verify all points against all facets if op count is smaller
+
+ notes:
+ if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="INITIALsearch">-</a>
+
+ qh_INITIALsearch
+ if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="INITIALmax">-</a>
+
+ qh_INITIALmax
+ if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+
+ notes:
+ from points with non-zero determinants
+ use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEdefault">-</a>
+
+ qh_JOGGLEdefault
+ default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+ notes:
+ rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+ rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+ rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+ rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+ rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+ rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+ rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+ rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+ rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+ the later have about 20 points per facet, each of which may interfere
+
+ pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEincrease">-</a>
+
+ qh_JOGGLEincrease
+ factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEretry">-</a>
+
+ qh_JOGGLEretry
+ if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+ notes:
+ try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEagain">-</a>
+
+ qh_JOGGLEagain
+ every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+ notes:
+ 1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEmaxincrease">-</a>
+
+ qh_JOGGLEmaxincrease
+ maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+ relative to qh.MAXwidth
+
+ notes:
+ qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="JOGGLEmaxretry">-</a>
+
+ qh_JOGGLEmaxretry
+ stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 100
+
+/*========= memory constants =========*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MEMalign">-</a>
+
+ qh_MEMalign
+ memory alignment for qh_meminitbuffers() in global.c
+
+ notes:
+ 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 using gcc, best alignment is
+ #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign fmax_(sizeof(realT), sizeof(void *))
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MEMbufsize">-</a>
+
+ qh_MEMbufsize
+ size of additional memory buffers
+
+ notes:
+ used for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMbufsize 0x10000 /* allocate 64K memory buffers */
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MEMinitbuf">-</a>
+
+ qh_MEMinitbuf
+ size of initial memory buffer
+
+ notes:
+ use for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMinitbuf 0x20000 /* initially allocate 128K buffer */
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="INFINITE">-</a>
+
+ qh_INFINITE
+ on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE -10.101
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DEFAULTbox">-</a>
+
+ qh_DEFAULTbox
+ default box size (Geomview expects 0.5)
+*/
+#define qh_DEFAULTbox 0.5
+
+/*======= conditional compilation ============================*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="compiler">-</a>
+
+ __cplusplus
+ defined by C++ compilers
+
+ __MSC_VER
+ defined by Microsoft Visual C++
+
+ __MWERKS__ && __POWERPC__
+ defined by Metrowerks when compiling for the Power Macintosh
+
+ __STDC__
+ defined for strict ANSI C
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="COMPUTEfurthest">-</a>
+
+ qh_COMPUTEfurthest
+ compute furthest distance to an outside point instead of storing it with the facet
+ =1 to compute furthest
+
+ notes:
+ computing furthest saves memory but costs time
+ about 40% more distance tests for partitioning
+ removes facet->furthestdist
+*/
+#define qh_COMPUTEfurthest 0
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="KEEPstatistics">-</a>
+
+ qh_KEEPstatistics
+ =0 removes most of statistic gathering and reporting
+
+ notes:
+ if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 1
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXoutside">-</a>
+
+ qh_MAXoutside
+ record outer plane for each facet
+ =1 to record facet->maxoutside
+
+ notes:
+ this takes a realT per facet and slightly slows down qhull
+ it produces better outer planes for geomview output
+*/
+#define qh_MAXoutside 1
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="NOmerge">-</a>
+
+ qh_NOmerge
+ disables facet merging if defined
+
+ notes:
+ This saves about 10% space.
+
+ Unless 'Q0'
+ qh_NOmerge sets 'QJ' to avoid precision errors
+
+ #define qh_NOmerge
+
+ see:
+ <a href="mem.h#NOmem">qh_NOmem</a> in mem.c
+
+ see user.c/user_eg.c for removing io.o
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="NOtrace">-</a>
+
+ qh_NOtrace
+ no tracing if defined
+
+ notes:
+ This saves about 5% space.
+
+ #define qh_NOtrace
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="QHpointer">-</a>
+
+ qh_QHpointer
+ access global data with pointer or static structure
+
+ qh_QHpointer = 1 access globals via a pointer to allocated memory
+ enables qh_saveqhull() and qh_restoreqhull()
+ costs about 8% in time and 2% in space
+
+ = 0 qh_qh and qh_qhstat are static data structures
+ only one instance of qhull() can be active at a time
+ default value
+
+ notes:
+ all global variables for qhull are in qh, qhmem, and qhstat
+ qh is defined in qhull.h
+ qhmem is defined in mem.h
+ qhstat is defined in stat.h
+
+ see:
+ user_eg.c for an example
+*/
+#define qh_QHpointer 0
+#if 0 /* sample code */
+ qhT *oldqhA, *oldqhB;
+
+ exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ /* use results from first call to qh_new_qhull */
+ oldqhA= qh_save_qhull();
+ exitcode= qh_new_qhull (dimB, numpointsB, pointsB, ismalloc,
+ flags, outfile, errfile);
+ /* use results from second call to qh_new_qhull */
+ oldqhB= qh_save_qhull();
+ qh_restore_qhull (&oldqhA);
+ /* use results from first call to qh_new_qhull */
+ qh_freeqhull (qh_ALL); /* frees all memory used by first call */
+ qh_restore_qhull (&oldqhB);
+ /* use results from second call to qh_new_qhull */
+ qh_freeqhull (!qh_ALL); /* frees long memory used by second call */
+ qh_memfreeshort (&curlong, &totlong); /* frees short memory and memory allocator */
+#endif
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="QUICKhelp">-</a>
+
+ qh_QUICKhelp
+ =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp 0
+
+/* ============ -merge constants- ====================
+
+ These constants effect facet merging. You probably will not need
+ to modify these. They effect the performance of facet merging.
+*/
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DIMmergeVertex">-</a>
+
+ qh_DIMmergeVertex
+ max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DIMreduceBuild">-</a>
+
+ qh_DIMreduceBuild
+ max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="BESTcentrum">-</a>
+
+ qh_BESTcentrum
+ if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+ else, qh_findbestneighbor() tests all vertices (much better merges)
+
+ qh_BESTcentrum2
+ if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="BESTnonconvex">-</a>
+
+ qh_BESTnonconvex
+ if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+
+ notes:
+ It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXnewmerges">-</a>
+
+ qh_MAXnewmerges
+ if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+
+ notes:
+ It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXnewcentrum">-</a>
+
+ qh_MAXnewcentrum
+ if <= dim+n vertices (n approximates the number of merges),
+ reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+
+ notes:
+ needed to reduce cost and because centrums may move too much if
+ many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="COPLANARratio">-</a>
+
+ qh_COPLANARratio
+ for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+ notes:
+ for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="DISToutside">-</a>
+
+ qh_DISToutside
+ When is a point clearly outside of a facet?
+ Stops search in qh_findbestnew or qh_partitionall
+ qh_findbest uses qh.MINoutside since since it is only called if no merges.
+
+ notes:
+ 'Qf' always searches for best facet
+ if !qh.MERGING, same as qh.MINoutside.
+ if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+ [Note: Zdelvertextot occurs normally with interior points]
+ RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+ When there is a sharp edge, need to move points to a
+ clearly good facet; otherwise may be lost in another partitioning.
+ if too big then O(n^2) behavior for partitioning in cone
+ if very small then important points not processed
+ Needed in qh_partitionall for
+ RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+ Needed in qh_findbestnew for many instances of
+ RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+ See:
+ qh_DISToutside -- when is a point clearly outside of a facet
+ qh_SEARCHdist -- when is facet coplanar with the best facet?
+ qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+ fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="RATIOnearinside">-</a>
+
+ qh_RATIOnearinside
+ ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+ qh_check_maxout().
+
+ notes:
+ This is overkill since do not know the correct value.
+ It effects whether 'Qc' reports all coplanar points
+ Not used for 'd' since non-extreme points are coplanar
+*/
+#define qh_RATIOnearinside 5
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="SEARCHdist">-</a>
+
+ qh_SEARCHdist
+ When is a facet coplanar with the best facet?
+ qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+
+ See:
+ qh_DISToutside -- when is a point clearly outside of a facet
+ qh_SEARCHdist -- when is facet coplanar with the best facet?
+ qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+ (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="USEfindbestnew">-</a>
+
+ qh_USEfindbestnew
+ Always use qh_findbestnew for qh_partitionpoint, otherwise use
+ qh_findbestnew if merged new facet or sharpnewfacets.
+
+ See:
+ qh_DISToutside -- when is a point clearly outside of a facet
+ qh_SEARCHdist -- when is facet coplanar with the best facet?
+ qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="WIDEcoplanar">-</a>
+
+ qh_WIDEcoplanar
+ n*MAXcoplanar or n*MINvisible for a WIDEfacet
+
+ if vertex is further than qh.WIDEfacet from the hyperplane
+ then its ridges are not counted in computing the area, and
+ the facet's centrum is frozen.
+
+ notes:
+ qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+ qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="MAXnarrow">-</a>
+
+ qh_MAXnarrow
+ max. cosine in initial hull that sets qh.NARROWhull
+
+ notes:
+ If qh.NARROWhull, the initial partition does not make
+ coplanar points. If narrow, a coplanar point can be
+ coplanar to two facets of opposite orientations and
+ distant from the exact convex hull.
+
+ Conservative estimate. Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="WARNnarrow">-</a>
+
+ qh_WARNnarrow
+ max. cosine in initial hull to warn about qh.NARROWhull
+
+ notes:
+ this is a conservative estimate.
+ Don't actually see problems until it is -1.0. See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*-<a href="qh-user.htm#TOC"
+ >--------------------------------</a><a name="ZEROdelaunay">-</a>
+
+ qh_ZEROdelaunay
+ a zero Delaunay facet occurs for input sites coplanar with their convex hull
+ the last normal coefficient of a zero Delaunay facet is within
+ qh_ZEROdelaunay * qh.ANGLEround of 0
+
+ notes:
+ qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+ You can avoid zero Delaunay facets by surrounding the input with a box.
+
+ Use option 'PDk:-n' to explicitly define zero Delaunay facets
+ k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+ n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+#endif /* qh_DEFuser */
+
+
+
diff --git a/extern/qhull/src/user_eg.c b/extern/qhull/src/user_eg.c
new file mode 100755
index 00000000000..97e4aa7a89a
--- /dev/null
+++ b/extern/qhull/src/user_eg.c
@@ -0,0 +1,310 @@
+/*<html><pre> -<a href="qh-user.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ user_eg.c
+ sample code for calling qhull() from an application
+
+ call with:
+
+ user_eg "cube/diamond options" "delaunay options" "halfspace options"
+
+ for example:
+
+ user_eg # return summaries
+
+ user_eg "n" "o" "Fp" # return normals, OFF, points
+
+ user_eg "n Qt" "o" "Fp" # triangulated cube
+
+ user_eg "QR0 p" "QR0 v p" "QR0 Fp" # rotate input and return points
+ # 'v' returns Voronoi
+ # transform is rotated for halfspaces
+
+ main() makes three runs of qhull.
+
+ 1) compute the convex hull of a cube
+
+ 2a) compute the Delaunay triangulation of random points
+
+ 2b) find the Delaunay triangle closest to a point.
+
+ 3) compute the halfspace intersection of a diamond
+
+ notes:
+
+ For another example, see main() in unix.c and user_eg2.c.
+ These examples, call qh_qhull() directly. They allow
+ tighter control on the code loaded with Qhull.
+
+ For a simple C++ example, see qhull_interface.cpp
+
+ Summaries are sent to stderr if other output formats are used
+
+ compiled by 'make user_eg'
+
+ see qhull.h for data structures, macros, and user-callable functions.
+*/
+
+#include "qhull_a.h"
+
+/*-------------------------------------------------
+-internal function prototypes
+*/
+void print_summary (void);
+void makecube (coordT *points, int numpoints, int dim);
+void makeDelaunay (coordT *points, int numpoints, int dim, int seed);
+void findDelaunay (int dim);
+void makehalf (coordT *points, int numpoints, int dim);
+
+/*-------------------------------------------------
+-print_summary()
+*/
+void print_summary (void) {
+ facetT *facet;
+ int k;
+
+ printf ("\n%d vertices and %d facets with normals:\n",
+ qh num_vertices, qh num_facets);
+ FORALLfacets {
+ for (k=0; k < qh hull_dim; k++)
+ printf ("%6.2g ", facet->normal[k]);
+ printf ("\n");
+ }
+}
+
+/*--------------------------------------------------
+-makecube- set points to vertices of cube
+ points is numpoints X dim
+*/
+void makecube (coordT *points, int numpoints, int dim) {
+ int j,k;
+ coordT *point;
+
+ for (j=0; j<numpoints; j++) {
+ point= points + j*dim;
+ for (k=dim; k--; ) {
+ if (j & ( 1 << k))
+ point[k]= 1.0;
+ else
+ point[k]= -1.0;
+ }
+ }
+} /*.makecube.*/
+
+/*--------------------------------------------------
+-makeDelaunay- set points for dim Delaunay triangulation of random points
+ points is numpoints X dim.
+notes:
+ makeDelaunay() in user_eg2.c uses qh_setdelaunay() to project points in place.
+*/
+void makeDelaunay (coordT *points, int numpoints, int dim, int seed) {
+ int j,k;
+ coordT *point, realr;
+
+
+ printf ("seed: %d\n", seed);
+ qh_RANDOMseed_( seed);
+ for (j=0; j<numpoints; j++) {
+ point= points + j*dim;
+ for (k= 0; k < dim; k++) {
+ realr= qh_RANDOMint;
+ point[k]= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+ }
+ }
+} /*.makeDelaunay.*/
+
+/*--------------------------------------------------
+-findDelaunay- find Delaunay triangle for [0.5,0.5,...]
+ assumes dim < 100
+notes:
+ calls qh_setdelaunay() to project the point to a parabaloid
+*/
+void findDelaunay (int dim) {
+ int k;
+ coordT point[ 100];
+ boolT isoutside;
+ realT bestdist;
+ facetT *facet;
+ vertexT *vertex, **vertexp;
+
+ for (k= 0; k < dim; k++)
+ point[k]= 0.5;
+ qh_setdelaunay (dim+1, 1, point);
+ facet= qh_findbestfacet (point, qh_ALL, &bestdist, &isoutside);
+ FOREACHvertex_(facet->vertices) {
+ for (k=0; k < dim; k++)
+ printf ("%5.2f ", vertex->point[k]);
+ printf ("\n");
+ }
+} /*.findDelaunay.*/
+
+/*--------------------------------------------------
+-makehalf- set points to halfspaces for a (dim)-dimensional diamond
+ points is numpoints X dim+1
+
+ each halfspace consists of dim coefficients followed by an offset
+*/
+void makehalf (coordT *points, int numpoints, int dim) {
+ int j,k;
+ coordT *point;
+
+ for (j=0; j<numpoints; j++) {
+ point= points + j*(dim+1);
+ point[dim]= -1.0; /* offset */
+ for (k=dim; k--; ) {
+ if (j & ( 1 << k))
+ point[k]= 1.0;
+ else
+ point[k]= -1.0;
+ }
+ }
+} /*.makehalf.*/
+
+#define DIM 3 /* dimension of points, must be < 31 for SIZEcube */
+#define SIZEcube (1<<DIM)
+#define SIZEdiamond (2*DIM)
+#define TOTpoints (SIZEcube + SIZEdiamond)
+
+/*--------------------------------------------------
+-main- derived from call_qhull in user.c
+
+ see program header
+
+ this contains three runs of Qhull for convex hull, Delaunay
+ triangulation or Voronoi vertices, and halfspace intersection
+
+*/
+int main (int argc, char *argv[]) {
+ int dim= DIM; /* dimension of points */
+ int numpoints; /* number of points */
+ coordT points[(DIM+1)*TOTpoints]; /* array of coordinates for each point */
+ coordT *rows[TOTpoints];
+ boolT ismalloc= False; /* True if qhull should free points in qh_freeqhull() or reallocation */
+ char flags[250]; /* option flags for qhull, see qh_opt.htm */
+ FILE *outfile= stdout; /* output from qh_produce_output()
+ use NULL to skip qh_produce_output() */
+ FILE *errfile= stderr; /* error messages from qhull code */
+ int exitcode; /* 0 if no error from qhull */
+ facetT *facet; /* set by FORALLfacets */
+ int curlong, totlong; /* memory remaining after qh_memfreeshort */
+ int i;
+
+ printf ("This is the output from user_eg.c\n\n\
+It shows how qhull() may be called from an application. It is not part\n\
+of qhull itself. If it appears accidently, please remove user_eg.c from\n\
+your project.\n\n");
+
+ /*
+ Run 1: convex hull
+ */
+ printf( "\ncompute convex hull of cube after rotating input\n");
+ sprintf (flags, "qhull s Tcv %s", argc >= 2 ? argv[1] : "");
+ numpoints= SIZEcube;
+ makecube (points, numpoints, DIM);
+ for (i=numpoints; i--; )
+ rows[i]= points+dim*i;
+ qh_printmatrix (outfile, "input", rows, numpoints, dim);
+ exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ if (!exitcode) { /* if no error */
+ /* 'qh facet_list' contains the convex hull */
+ print_summary();
+ FORALLfacets {
+ /* ... your code ... */
+ }
+ }
+ qh_freeqhull(!qh_ALL); /* free long memory */
+ qh_memfreeshort (&curlong, &totlong); /* free short memory and memory allocator */
+ if (curlong || totlong)
+ fprintf (errfile, "qhull internal warning (user_eg, #1): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+
+ /*
+ Run 2: Delaunay triangulation
+ */
+
+ printf( "\ncompute 3-d Delaunay triangulation\n");
+ sprintf (flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+ numpoints= SIZEcube;
+ makeDelaunay (points, numpoints, dim, time(NULL));
+ for (i=numpoints; i--; )
+ rows[i]= points+dim*i;
+ qh_printmatrix (outfile, "input", rows, numpoints, dim);
+ exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ if (!exitcode) { /* if no error */
+ /* 'qh facet_list' contains the convex hull */
+ /* If you want a Voronoi diagram ('v') and do not request output (i.e., outfile=NULL),
+ call qh_setvoronoi_all() after qh_new_qhull(). */
+ print_summary();
+ FORALLfacets {
+ /* ... your code ... */
+ }
+ printf( "\nfind 3-d Delaunay triangle closest to [0.5, 0.5, ...]\n");
+ exitcode= setjmp (qh errexit);
+ if (!exitcode) {
+ /* Trap Qhull errors in findDelaunay(). Without the setjmp(), Qhull
+ will exit() after reporting an error */
+ qh NOerrexit= False;
+ findDelaunay (DIM);
+ }
+ qh NOerrexit= True;
+ }
+#if qh_QHpointer /* see user.h */
+ {
+ qhT *oldqhA, *oldqhB;
+ coordT pointsB[DIM*TOTpoints]; /* array of coordinates for each point */
+
+
+ printf( "\nsave first triangulation and compute a new triangulation\n");
+ oldqhA= qh_save_qhull();
+ sprintf (flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+ numpoints= SIZEcube;
+ makeDelaunay (pointsB, numpoints, dim, time(NULL)+1);
+ for (i=numpoints; i--; )
+ rows[i]= pointsB+dim*i;
+ qh_printmatrix (outfile, "input", rows, numpoints, dim);
+ exitcode= qh_new_qhull (dim, numpoints, pointsB, ismalloc,
+ flags, outfile, errfile);
+ if (!exitcode)
+ print_summary();
+ printf( "\nsave second triangulation and restore first one\n");
+ oldqhB= qh_save_qhull();
+ qh_restore_qhull (&oldqhA);
+ print_summary();
+ printf( "\nfree first triangulation and restore second one.\n");
+ qh_freeqhull (qh_ALL); /* free short and long memory used by first call */
+ /* do not use qh_memfreeshort */
+ qh_restore_qhull (&oldqhB);
+ print_summary();
+ }
+#endif
+ qh_freeqhull(!qh_ALL); /* free long memory */
+ qh_memfreeshort (&curlong, &totlong); /* free short memory and memory allocator */
+ if (curlong || totlong)
+ fprintf (errfile, "qhull internal warning (user_eg, #2): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+
+ /*
+ Run 3: halfspace intersection about the origin
+ */
+ printf( "\ncompute halfspace intersection about the origin for a diamond\n");
+ sprintf (flags, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "Fp");
+ numpoints= SIZEcube;
+ makehalf (points, numpoints, dim);
+ for (i=numpoints; i--; )
+ rows[i]= points+(dim+1)*i;
+ qh_printmatrix (outfile, "input as halfspace coefficients + offsets", rows, numpoints, dim+1);
+ /* use qh_sethalfspace_all to transform the halfspaces yourself.
+ If so, set 'qh feasible_point and do not use option 'Hn,...' [it would retransform the halfspaces]
+ */
+ exitcode= qh_new_qhull (dim+1, numpoints, points, ismalloc,
+ flags, outfile, errfile);
+ if (!exitcode)
+ print_summary();
+ qh_freeqhull (!qh_ALL);
+ qh_memfreeshort (&curlong, &totlong);
+ if (curlong || totlong) /* could also check previous runs */
+ fprintf (stderr, "qhull internal warning (user_eg, #3): did not free %d bytes of long memory (%d pieces)\n",
+ totlong, curlong);
+ return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/user_eg2.c b/extern/qhull/src/user_eg2.c
new file mode 100755
index 00000000000..1eb42ccfe8a
--- /dev/null
+++ b/extern/qhull/src/user_eg2.c
@@ -0,0 +1,532 @@
+/*<html><pre> -<a href="qh-qhull.htm"
+ >-------------------------------</a><a name="TOP">-</a>
+
+ user_eg2.c
+
+ sample code for calling qhull() from an application.
+
+ See user_eg.c for a simpler method using qh_new_qhull().
+ The method used here and in unix.c gives you additional
+ control over Qhull.
+
+ call with:
+
+ user_eg2 "triangulated cube/diamond options" "delaunay options" "halfspace options"
+
+ for example:
+
+ user_eg2 # return summaries
+
+ user_eg2 "n" "o" "Fp" # return normals, OFF, points
+
+ user_eg2 "QR0 p" "QR0 v p" "QR0 Fp" # rotate input and return points
+ # 'v' returns Voronoi
+ # transform is rotated for halfspaces
+
+ main() makes three runs of qhull.
+
+ 1) compute the convex hull of a cube, and incrementally add a diamond
+
+ 2a) compute the Delaunay triangulation of random points, and add points.
+
+ 2b) find the Delaunay triangle closest to a point.
+
+ 3) compute the halfspace intersection of a diamond, and add a cube
+
+ notes:
+
+ summaries are sent to stderr if other output formats are used
+
+ derived from unix.c and compiled by 'make user_eg2'
+
+ see qhull.h for data structures, macros, and user-callable functions.
+
+ If you want to control all output to stdio and input to stdin,
+ set the #if below to "1" and delete all lines that contain "io.c".
+ This prevents the loading of io.o. Qhull will
+ still write to 'qh ferr' (stderr) for error reporting and tracing.
+
+ Defining #if 1, also prevents user.o from being loaded.
+*/
+
+#include "qhull_a.h"
+
+/*-------------------------------------------------
+-internal function prototypes
+*/
+void print_summary (void);
+void makecube (coordT *points, int numpoints, int dim);
+void adddiamond (coordT *points, int numpoints, int numnew, int dim);
+void makeDelaunay (coordT *points, int numpoints, int dim);
+void addDelaunay (coordT *points, int numpoints, int numnew, int dim);
+void findDelaunay (int dim);
+void makehalf (coordT *points, int numpoints, int dim);
+void addhalf (coordT *points, int numpoints, int numnew, int dim, coordT *feasible);
+
+/*-------------------------------------------------
+-print_summary()
+*/
+void print_summary (void) {
+ facetT *facet;
+ int k;
+
+ printf ("\n%d vertices and %d facets with normals:\n",
+ qh num_vertices, qh num_facets);
+ FORALLfacets {
+ for (k=0; k < qh hull_dim; k++)
+ printf ("%6.2g ", facet->normal[k]);
+ printf ("\n");
+ }
+}
+
+/*--------------------------------------------------
+-makecube- set points to vertices of cube
+ points is numpoints X dim
+*/
+void makecube (coordT *points, int numpoints, int dim) {
+ int j,k;
+ coordT *point;
+
+ for (j=0; j<numpoints; j++) {
+ point= points + j*dim;
+ for (k=dim; k--; ) {
+ if (j & ( 1 << k))
+ point[k]= 1.0;
+ else
+ point[k]= -1.0;
+ }
+ }
+} /*.makecube.*/
+
+/*--------------------------------------------------
+-adddiamond- add diamond to convex hull
+ points is numpoints+numnew X dim.
+
+notes:
+ qh_addpoint() does not make a copy of the point coordinates.
+
+ For inside points and some outside points, qh_findbestfacet performs
+ an exhaustive search for a visible facet. Algorithms that retain
+ previously constructed hulls should be faster for on-line construction
+ of the convex hull.
+*/
+void adddiamond (coordT *points, int numpoints, int numnew, int dim) {
+ int j,k;
+ coordT *point;
+ facetT *facet;
+ boolT isoutside;
+ realT bestdist;
+
+ for (j= 0; j < numnew ; j++) {
+ point= points + (numpoints+j)*dim;
+ if (points == qh first_point) /* in case of 'QRn' */
+ qh num_points= numpoints+j+1;
+ /* qh num_points sets the size of the points array. You may
+ allocate the points elsewhere. If so, qh_addpoint records
+ the point's address in qh other_points
+ */
+ for (k=dim; k--; ) {
+ if (j/2 == k)
+ point[k]= (j & 1) ? 2.0 : -2.0;
+ else
+ point[k]= 0.0;
+ }
+ facet= qh_findbestfacet (point, !qh_ALL, &bestdist, &isoutside);
+ if (isoutside) {
+ if (!qh_addpoint (point, facet, False))
+ break; /* user requested an early exit with 'TVn' or 'TCn' */
+ }
+ printf ("%d vertices and %d facets\n",
+ qh num_vertices, qh num_facets);
+ /* qh_produce_output(); */
+ }
+ if (qh DOcheckmax)
+ qh_check_maxout();
+ else if (qh KEEPnearinside)
+ qh_nearcoplanar();
+} /*.adddiamond.*/
+
+/*--------------------------------------------------
+-makeDelaunay- set points for dim-1 Delaunay triangulation of random points
+ points is numpoints X dim. Each point is projected to a paraboloid.
+*/
+void makeDelaunay (coordT *points, int numpoints, int dim) {
+ int j,k, seed;
+ coordT *point, realr;
+
+ seed= time(NULL);
+ printf ("seed: %d\n", seed);
+ qh_RANDOMseed_( seed);
+ for (j=0; j<numpoints; j++) {
+ point= points + j*dim;
+ for (k= 0; k < dim-1; k++) {
+ realr= qh_RANDOMint;
+ point[k]= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+ }
+ }
+ qh_setdelaunay (dim, numpoints, points);
+} /*.makeDelaunay.*/
+
+/*--------------------------------------------------
+-addDelaunay- add points to dim-1 Delaunay triangulation
+ points is numpoints+numnew X dim. Each point is projected to a paraboloid.
+notes:
+ qh_addpoint() does not make a copy of the point coordinates.
+
+ Since qh_addpoint() is not given a visible facet, it performs a directed
+ search of all facets. Algorithms that retain previously
+ constructed hulls may be faster.
+*/
+void addDelaunay (coordT *points, int numpoints, int numnew, int dim) {
+ int j,k;
+ coordT *point, realr;
+ facetT *facet;
+ realT bestdist;
+ boolT isoutside;
+
+ for (j= 0; j < numnew ; j++) {
+ point= points + (numpoints+j)*dim;
+ if (points == qh first_point) /* in case of 'QRn' */
+ qh num_points= numpoints+j+1;
+ /* qh num_points sets the size of the points array. You may
+ allocate the point elsewhere. If so, qh_addpoint records
+ the point's address in qh other_points
+ */
+ for (k= 0; k < dim-1; k++) {
+ realr= qh_RANDOMint;
+ point[k]= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+ }
+ qh_setdelaunay (dim, 1, point);
+ facet= qh_findbestfacet (point, !qh_ALL, &bestdist, &isoutside);
+ if (isoutside) {
+ if (!qh_addpoint (point, facet, False))
+ break; /* user requested an early exit with 'TVn' or 'TCn' */
+ }
+ qh_printpoint (stdout, "added point", point);
+ printf ("%d points, %d extra points, %d vertices, and %d facets in total\n",
+ qh num_points, qh_setsize (qh other_points),
+ qh num_vertices, qh num_facets);
+
+ /* qh_produce_output(); */
+ }
+ if (qh DOcheckmax)
+ qh_check_maxout();
+ else if (qh KEEPnearinside)
+ qh_nearcoplanar();
+} /*.addDelaunay.*/
+
+/*--------------------------------------------------
+-findDelaunay- find Delaunay triangle for [0.5,0.5,...]
+ assumes dim < 100
+*/
+void findDelaunay (int dim) {
+ int k;
+ coordT point[ 100];
+ boolT isoutside;
+ realT bestdist;
+ facetT *facet;
+ vertexT *vertex, **vertexp;
+
+ for (k= 0; k < dim-1; k++)
+ point[k]= 0.5;
+ qh_setdelaunay (dim, 1, point);
+ facet= qh_findbestfacet (point, qh_ALL, &bestdist, &isoutside);
+ FOREACHvertex_(facet->vertices) {
+ for (k=0; k < dim-1; k++)
+ printf ("%5.2f ", vertex->point[k]);
+ printf ("\n");
+ }
+} /*.findDelaunay.*/
+
+/*--------------------------------------------------
+-makehalf- set points to halfspaces for a (dim)-d diamond
+ points is numpoints X dim+1
+
+ each halfspace consists of dim coefficients followed by an offset
+*/
+void makehalf (coordT *points, int numpoints, int dim) {
+ int j,k;
+ coordT *point;
+
+ for (j=0; j<numpoints; j++) {
+ point= points + j*(dim+1);
+ point[dim]= -1.0; /* offset */
+ for (k=dim; k--; ) {
+ if (j & ( 1 << k))
+ point[k]= 1.0;
+ else
+ point[k]= -1.0;
+ }
+ }
+} /*.makehalf.*/
+
+/*--------------------------------------------------
+-addhalf- add halfspaces for a (dim)-d cube to the intersection
+ points is numpoints+numnew X dim+1
+notes:
+ assumes dim < 100.
+
+ For makehalf(), points is the initial set of halfspaces with offsets.
+ It is transformed by qh_sethalfspace_all into a
+ (dim)-d set of newpoints. Qhull computed the convex hull of newpoints -
+ this is equivalent to the halfspace intersection of the
+ orginal halfspaces.
+
+ For addhalf(), the remainder of points stores the transforms of
+ the added halfspaces. Qhull computes the convex hull of newpoints
+ and the added points. qh_addpoint() does not make a copy of these points.
+
+ Since halfspace intersection is equivalent to a convex hull,
+ qh_findbestfacet may perform an exhaustive search
+ for a visible facet. Algorithms that retain previously constructed
+ intersections should be faster for on-line construction.
+*/
+void addhalf (coordT *points, int numpoints, int numnew, int dim, coordT *feasible) {
+ int j,k;
+ coordT *point, normal[100], offset, *next;
+ facetT *facet;
+ boolT isoutside;
+ realT bestdist;
+
+ for (j= 0; j < numnew ; j++) {
+ offset= -1.0;
+ for (k=dim; k--; ) {
+ if (j/2 == k) {
+ normal[k]= sqrt (dim); /* to normalize as in makehalf */
+ if (j & 1)
+ normal[k]= -normal[k];
+ }else
+ normal[k]= 0.0;
+ }
+ point= points + (numpoints+j)* (dim+1); /* does not use point[dim] */
+ qh_sethalfspace (dim, point, &next, normal, &offset, feasible);
+ facet= qh_findbestfacet (point, !qh_ALL, &bestdist, &isoutside);
+ if (isoutside) {
+ if (!qh_addpoint (point, facet, False))
+ break; /* user requested an early exit with 'TVn' or 'TCn' */
+ }
+ qh_printpoint (stdout, "added offset -1 and normal", normal);
+ printf ("%d points, %d extra points, %d vertices, and %d facets in total\n",
+ qh num_points, qh_setsize (qh other_points),
+ qh num_vertices, qh num_facets);
+ /* qh_produce_output(); */
+ }
+ if (qh DOcheckmax)
+ qh_check_maxout();
+ else if (qh KEEPnearinside)
+ qh_nearcoplanar();
+} /*.addhalf.*/
+
+#define DIM 3 /* dimension of points, must be < 31 for SIZEcube */
+#define SIZEcube (1<<DIM)
+#define SIZEdiamond (2*DIM)
+#define TOTpoints (SIZEcube + SIZEdiamond)
+
+/*--------------------------------------------------
+-main- derived from call_qhull in user.c
+
+ see program header
+
+ this contains three runs of Qhull for convex hull, Delaunay
+ triangulation or Voronoi vertices, and halfspace intersection
+
+*/
+int main (int argc, char *argv[]) {
+ boolT ismalloc;
+ int curlong, totlong, exitcode;
+ char options [2000];
+
+ printf ("This is the output from user_eg2.c\n\n\
+It shows how qhull() may be called from an application. It is not part\n\
+of qhull itself. If it appears accidently, please remove user_eg2.c from\n\
+your project.\n\n");
+ ismalloc= False; /* True if qh_freeqhull should 'free(array)' */
+ /*
+ Run 1: convex hull
+ */
+ qh_init_A (stdin, stdout, stderr, 0, NULL);
+ exitcode= setjmp (qh errexit);
+ if (!exitcode) {
+ coordT array[TOTpoints][DIM];
+
+ strcat (qh rbox_command, "user_eg cube");
+ sprintf (options, "qhull s Tcv Q11 %s ", argc >= 2 ? argv[1] : "");
+ qh_initflags (options);
+ printf( "\ncompute triangulated convex hull of cube after rotating input\n");
+ makecube (array[0], SIZEcube, DIM);
+ qh_init_B (array[0], SIZEcube, DIM, ismalloc);
+ qh_qhull();
+ qh_check_output();
+ qh_triangulate(); /* requires option 'Q11' if want to add points */
+ print_summary ();
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points ();
+ printf( "\nadd points in a diamond\n");
+ adddiamond (array[0], SIZEcube, SIZEdiamond, DIM);
+ qh_check_output();
+ print_summary ();
+ qh_produce_output(); /* delete this line to help avoid io.c */
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points ();
+ }
+ qh NOerrexit= True;
+ qh_freeqhull (!qh_ALL);
+ qh_memfreeshort (&curlong, &totlong);
+ /*
+ Run 2: Delaunay triangulation
+ */
+ qh_init_A (stdin, stdout, stderr, 0, NULL);
+ exitcode= setjmp (qh errexit);
+ if (!exitcode) {
+ coordT array[TOTpoints][DIM];
+
+ strcat (qh rbox_command, "user_eg Delaunay");
+ sprintf (options, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+ qh_initflags (options);
+ printf( "\ncompute 2-d Delaunay triangulation\n");
+ makeDelaunay (array[0], SIZEcube, DIM);
+ /* Instead of makeDelaunay with qh_setdelaunay, you may
+ produce a 2-d array of points, set DIM to 2, and set
+ qh PROJECTdelaunay to True. qh_init_B will call
+ qh_projectinput to project the points to the paraboloid
+ and add a point "at-infinity".
+ */
+ qh_init_B (array[0], SIZEcube, DIM, ismalloc);
+ qh_qhull();
+ /* If you want Voronoi ('v') without qh_produce_output(), call
+ qh_setvoronoi_all() after qh_qhull() */
+ qh_check_output();
+ print_summary ();
+ qh_produce_output(); /* delete this line to help avoid io.c */
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points ();
+ printf( "\nadd points to triangulation\n");
+ addDelaunay (array[0], SIZEcube, SIZEdiamond, DIM);
+ qh_check_output();
+ qh_produce_output(); /* delete this line to help avoid io.c */
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points ();
+ printf( "\nfind Delaunay triangle closest to [0.5, 0.5, ...]\n");
+ findDelaunay (DIM);
+ }
+ qh NOerrexit= True;
+ qh_freeqhull (!qh_ALL);
+ qh_memfreeshort (&curlong, &totlong);
+ /*
+ Run 3: halfspace intersection
+ */
+ qh_init_A (stdin, stdout, stderr, 0, NULL);
+ exitcode= setjmp (qh errexit);
+ if (!exitcode) {
+ coordT array[TOTpoints][DIM+1]; /* +1 for halfspace offset */
+ pointT *points;
+
+ strcat (qh rbox_command, "user_eg halfspaces");
+ sprintf (options, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "");
+ qh_initflags (options);
+ printf( "\ncompute halfspace intersection about the origin for a diamond\n");
+ makehalf (array[0], SIZEcube, DIM);
+ qh_setfeasible (DIM); /* from io.c, sets qh feasible_point from 'Hn,n' */
+ /* you may malloc and set qh feasible_point directly. It is only used for
+ option 'Fp' */
+ points= qh_sethalfspace_all ( DIM+1, SIZEcube, array[0], qh feasible_point);
+ qh_init_B (points, SIZEcube, DIM, True); /* qh_freeqhull frees points */
+ qh_qhull();
+ qh_check_output();
+ qh_produce_output(); /* delete this line to help avoid io.c */
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points ();
+ printf( "\nadd halfspaces for cube to intersection\n");
+ addhalf (array[0], SIZEcube, SIZEdiamond, DIM, qh feasible_point);
+ qh_check_output();
+ qh_produce_output(); /* delete this line to help avoid io.c */
+ if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+ qh_check_points ();
+ }
+ qh NOerrexit= True;
+ qh NOerrexit= True;
+ qh_freeqhull (!qh_ALL);
+ qh_memfreeshort (&curlong, &totlong);
+ if (curlong || totlong) /* could also check previous runs */
+ fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+ totlong, curlong);
+ return exitcode;
+} /* main */
+
+#if 1 /* use 1 to prevent loading of io.o and user.o */
+/*-------------------------------------------
+-errexit- return exitcode to system after an error
+ assumes exitcode non-zero
+ prints useful information
+ see qh_errexit2() in qhull.c for 2 facets
+*/
+void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
+
+ if (qh ERREXITcalled) {
+ fprintf (qh ferr, "qhull error while processing previous error. Exit program\n");
+ exit(1);
+ }
+ qh ERREXITcalled= True;
+ if (!qh QHULLfinished)
+ qh hulltime= (unsigned)clock() - qh hulltime;
+ fprintf (qh ferr, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
+ fprintf(qh ferr, "Options selected:\n%s\n", qh qhull_options);
+ if (qh furthest_id >= 0) {
+ fprintf(qh ferr, "\nLast point added to hull was p%d", qh furthest_id);
+ if (zzval_(Ztotmerge))
+ fprintf(qh ferr, " Last merge was #%d.", zzval_(Ztotmerge));
+ if (qh QHULLfinished)
+ fprintf(qh ferr, "\nQhull has finished constructing the hull.");
+ else if (qh POSTmerging)
+ fprintf(qh ferr, "\nQhull has started post-merging");
+ fprintf(qh ferr, "\n\n");
+ }
+ if (qh NOerrexit) {
+ fprintf (qh ferr, "qhull error while ending program. Exit program\n");
+ exit(1);
+ }
+ if (!exitcode)
+ exitcode= qh_ERRqhull;
+ qh NOerrexit= True;
+ longjmp(qh errexit, exitcode);
+} /* errexit */
+
+
+/*-------------------------------------------
+-errprint- prints out the information of the erroneous object
+ any parameter may be NULL, also prints neighbors and geomview output
+*/
+void qh_errprint(char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+
+ fprintf (qh ferr, "%s facets f%d f%d ridge r%d vertex v%d\n",
+ string, getid_(atfacet), getid_(otherfacet), getid_(atridge),
+ getid_(atvertex));
+} /* errprint */
+
+
+void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
+ facetT *facet, **facetp;
+
+ /* remove these calls to help avoid io.c */
+ qh_printbegin (qh ferr, qh_PRINTfacets, facetlist, facets, printall);/*io.c*/
+ FORALLfacet_(facetlist) /*io.c*/
+ qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall); /*io.c*/
+ FOREACHfacet_(facets) /*io.c*/
+ qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall); /*io.c*/
+ qh_printend (qh ferr, qh_PRINTfacets, facetlist, facets, printall); /*io.c*/
+
+ FORALLfacet_(facetlist)
+ fprintf( qh ferr, "facet f%d\n", facet->id);
+} /* printfacetlist */
+
+
+
+/*-----------------------------------------
+-user_memsizes- allocate up to 10 additional, quick allocation sizes
+*/
+void qh_user_memsizes (void) {
+
+ /* qh_memsize (size); */
+} /* user_memsizes */
+
+#endif